openpyxl: ValueError: I/O operation on closed file

Question:

I used this code to put an image logo.png in logo.xlsx at cell A1:

from openpyxl import Workbook
from openpyxl.drawing.image import Image
wb = Workbook()
ws = wb.active
img = Image('logo.png')
ws.add_image(img, 'A1')
wb.save('logo.xlsx')

now I am trying to read this file as existing workbook using load_workbook, using this code:

from openpyxl import load_workbook
wb = load_workbook('./logo.xlsx')
wb.save('logo_new.xlsx')

but I am getting following error:

Traceback (most recent call last):
  File "c:UsersSarmad GulzarDocumentsVisual Studio CodePythonExceltest.py", line 3, in <module>
    wb.save("new3.xlsx")
  File "C:Python37libsite-packagesopenpyxlworkbookworkbook.py", line 391, in save
    save_workbook(self, filename)
  File "C:Python37libsite-packagesopenpyxlwriterexcel.py", line 284, in save_workbook
    writer.save(filename)
  File "C:Python37libsite-packagesopenpyxlwriterexcel.py", line 266, in save
    self.write_data()
  File "C:Python37libsite-packagesopenpyxlwriterexcel.py", line 85, in write_data
    self._write_images()
  File "C:Python37libsite-packagesopenpyxlwriterexcel.py", line 122, in _write_images
    self._archive.writestr(img.path[1:], img._data())
  File "C:Python37libsite-packagesopenpyxldrawingimage.py", line 64, in _data
    img = _import_image(self.ref)
  File "C:Python37libsite-packagesopenpyxldrawingimage.py", line 33, in _import_image
    img = PILImage.open(img)
  File "C:Python37libsite-packagesPILImage.py", line 2638, in open
    fp.seek(0)
ValueError: I/O operation on closed file.

P.S: I tried doing the same thing to a file which had no images. It worked just fine.

Asked By: Sarmad Gulzar

||

Answers:

I was using openpyxl version 2.5.14. Downgrading to 2.5.11 fixed it. More information here.

Answered By: Sarmad Gulzar

After wasting time by searching for a fix, this was my solution:
I had the same problem with openpyxl 2.5.14, but downgrading on 2.5.11 don’t solve the problem at all, use 2.5.12 instead.

https://bitbucket.org/openpyxl/openpyxl/issues/1133/writing-xlsx-image-is-not-inserted-and

If you use 2.5.11 it is possible that no new image will display on your excel file.
this is a known problem if there are already images in the file to edit.

Best practise:
If the rest of your code runs with openpyxl 2.6.2 or 2.6.1 use one of this versions, here this problem is solved by a library update!

https://openpyxl.readthedocs.io/en/stable/changes.html
fixed on version 2.6.0 issue #1170

Answered By: droebi

I am hitting this error in openpyxl 3.1.2, when trying to add images that I have in memory. The issue is how drawing.images.Image._data works, where it tries to reaccess the underlying image, which it can’t in the in-memory case. Here is my solution, which overrides the _data:

def add_img_bytes_to_sheet(sheet: Worksheet, cell: Cell, img_bytes: bytes) -> None:
    """Add image bytes to a cell, wrapping how the data is accessed.
    
    Otherwise, there is a "IO on closed file" error. We overwrite the `_data()`
    method on an openpyxl image, making sure that the wrapper is independent for
    each image.
    """
    bio = BytesIO(img_bytes)
    pilimage = PIL.Image.open(bio)
    image = openpyxl.drawing.image.Image(pilimage)
    def data_fillin(imgb: bytes) -> Callable[[], bytes]:
        bobj = bytes(imgb)
        def wrap() -> bytes:
            return bobj
        return wrap
    image._data = data_fillin(img_bytes)
    image.anchor = f"{cell.column_letter}{cell.row}"
    sheet.add_image(image)
    return
Answered By: Yakov Pechersky
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.