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.
Answers:
I was using openpyxl version 2.5.14. Downgrading to 2.5.11 fixed it. More information here.
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
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
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.
I was using openpyxl version 2.5.14. Downgrading to 2.5.11 fixed it. More information here.
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
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