1

I just want to open the image files in a folder, and convert them to jpeg if they are not already jpeg. Only thing is I need to save the file in memory, not to file. The reason is, in fact I'm reading the images from tfrecod file (tensorflow data file format), extract the image from it, check the file format, if not jpeg, convert to jpeg and then write back to tfrecord file after decoding properly. Because tensorflow object detection api doesn't accept any image format than jpeg unfortunately. Anyways, that's just the explanation why I need it.

To be able to do that, I need to keep the file in memory. So here is my code:

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)

When I run this, I get ValueError: I/O operation on closed file. on the line

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

Any idea why this gives error? I saw this as suggested way to write in memory file: How to write PNG image to string with the PIL?

martineau
  • 119,623
  • 25
  • 170
  • 301
Ahmet Cetin
  • 3,683
  • 3
  • 25
  • 34
  • I believe the linked answer suggesting how to write a memory file is wrong. I suggest you edit your question and get rid of the tensorflow and tfrecod file stuff — which has nothing to do what you're really asking — and provide a [mre] that others can easily run (and modify to show you how to do it properly). – martineau May 29 '20 at 16:29
  • Have you tried wrapping your open code with an ```with open('...', 'w') as f:``` – bones225 May 29 '20 at 16:41

1 Answers1

4

The error is not about tempFile but about stream. You should not do stream.close() until you are done with image. This is a lazy API, so it can handle large images more efficiently.

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)

From the Pillow's 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).

Ronald
  • 1,009
  • 6
  • 13