Использование `wb.save` приводит к" UnboundLocalError: локальная переменная 'rel', на которую ссылаются до назначения " - PullRequest
0 голосов
/ 12 апреля 2020

Я пытаюсь узнать, как разместить изображение на листе Excel, но у меня проблема с wb.save. Моя программа заканчивается следующей ошибкой:

"C:\Users\Don\PycharmProjects\Test 2\venv\Scripts\python.exe" "C:/Users/Don/PycharmProjects/Test 2/Test 2.py"
Traceback (most recent call last):
  File "C:/Users/Don/PycharmProjects/Test 2/Test 2.py", line 20, in <module>
    wb.save('POKENO Cards new.xlsx')
  File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\workbook\workbook.py", line 392, in save
    save_workbook(self, filename)
  File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\writer\excel.py", line 293, in save_workbook
    writer.save()
  File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\writer\excel.py", line 275, in save
    self.write_data()
  File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\writer\excel.py", line 75, in write_data
    self._write_worksheets()
  File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\writer\excel.py", line 218, in _write_worksheets
    self._write_drawing(ws._drawing)
  File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\writer\excel.py", line 141, in _write_drawing
    self._archive.writestr(drawing.path[1:], tostring(drawing._write()))
  File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\drawing\spreadsheet_drawing.py", line 295, in _write
    self._rels.append(rel)
UnboundLocalError: local variable 'rel' referenced before assignment

Process finished with exit code 1

Это мой код. Работает до последнего утверждения.

import openpyxl as xl
from PIL import Image
#im = Image.open(r"Playing Cards/2C.jpg")
im = Image.open(r"C:/Users/Don/Pictures/resized Nyle.jpg")
wb = xl.load_workbook(filename="C:/Users/Don/PycharmProjects/Test 2/POKENO   Cards.xlsx")
ws1 = wb.worksheets[0]
im.show()
img = im.resize((78, 100))
img.show()
wb2 = xl.load_workbook(filename="C:/Users/Don/PycharmProjects/Test 2/POKENO Cards new.xlsx")
ws2 = wb2.active
ws2.add_image(im, 'A4')
wb2.save(filename="C:/Users/Don/PycharmProjects/Test 2/POKENO Cards new.xlsx")

1 Ответ

0 голосов
/ 19 апреля 2020

Ошибка немного крипти c, но Traceback достаточно ясен, чтобы отследить причину проблемы: метод openpyxl add_image ожидает объект openpyxl.drawing.image.Image, а не изображение PIL.

Если вы проверите строки в openpyxl / drawing / spreadsheet_drawing.py , в которых возникла ошибка, есть проверка для типа изображения:

for idx, obj in enumerate(self.charts + self.images, 1):
    anchor = _check_anchor(obj)
    if isinstance(obj, ChartBase):
        rel = Relationship(type="chart", Target=obj.path)
        ...
    elif isinstance(obj, Image):
        rel = Relationship(type="image", Target=obj.path)
        ...

    anchors.append(anchor)
    self._rels.append(rel)

Проблема в том, что ваша код

im = Image.open(r"C:/Users/Don/Pictures/resized Nyle.jpg")
...
ws2.add_image(im, 'A4')

передан в im, который имеет тип 'PIL.PngImagePlugin.PngImageFile'. Это не ChartBase или собственный тип Image openpyxl. Таким образом, rel никогда не будет инициализироваться, что приведет к ошибке, что rel использовался перед присвоением чего-либо: " UnboundLocalError: локальная переменная 'rel' ссылалась до назначения ... ".

Если вы отметите openpyxl / drawing / image , вы можете заметить, что openpyxl Image - это просто оболочка для PIL Image. Он нуждается в объекте PIL.Image.Image и внутренне вызывает PILImage.open(img) для переданного объекта изображения, если он не один.

Так что вы можете подумать, что преобразование img в * open32xl Image может работать.

import openpyxl as xl
from openpyxl import Workbook
from openpyxl.drawing.image import Image as XLImage
from PIL import Image as PILImage

im = PILImage.open("my_input_image.png")
pil_img = im.resize((78, 100))
xl_img = XLImage(pil_img)

wb2 = Workbook()
ws2 = wb2.active
ws2.add_image(xl_img, 'A1')
wb2.save(filename="output.xlsx")

Это решит исходную ошибку, но тогда вы получите новую ошибку " Объект 'Image' не имеет атрибута 'fp'", который снова возвращается к модулю openpyxl Image , который ожидает, что объект изображения имеет атрибут fp, который доступен только если изображение было создано из файла (то есть open(filename)).

Итак, я могу предложить следующее решение:

  1. Создать объект изображения как PIL Image
  2. Предварительная обработка изображения (например, изменение размера)
  3. Сохранение предварительно обработанного изображения обратно в файл
  4. Создание объекта изображения как изображения openpyxl
  5. Добавьте это изображение в рабочую книгу
from openpyxl import Workbook
from openpyxl.drawing.image import Image as XLImage
from PIL import Image as PILImage

im = PILImage.open("my_input_image.png")

pil_img = im.resize((78, 100))
pil_img.save("my_resized_image.png")

xl_img = XLImage("my_resized_image.png")

wb2 = Workbook()
ws2 = wb2.active
ws2.add_image(xl_img, 'A1')
wb2.save(filename="output.xlsx")

Если вам не нужно обрабатывать изображение перед добавлением изображения, просто откройте файл напрямую, используя класс Image openpyxl:

from openpyxl import Workbook
from openpyxl.drawing.image import Image as XLImage

xl_img = XLImage("my_input_image.png")

wb2 = Workbook()
ws2 = wb2.active
ws2.add_image(xl_img, 'A1')
wb2.save(filename="output.xlsx")
...