Использование модуля ImageDraw PIL - PullRequest
5 голосов
/ 31 января 2011

Я пытаюсь выполнять отдельные пиксельные манипуляции с помощью модуля ImageDraw PIL.Код ниже должен создать виджет холста Tkinter.Затем откройте изображение, измените цвет одного пикселя на красный, затем вставьте изображение в виджет холста.Однако, похоже, что он не работает.

Мой код:

import Tkinter
from PIL import ImageTk, Image, ImageDraw


class image_manip(Tkinter.Tk):

    def __init__(self):
        Tkinter.Tk.__init__(self)

        self.configure(bg='red')

        self.ImbImage = Tkinter.Canvas(self, highlightthickness=0, bd=0, bg='blue')
        self.ImbImage.pack()

        im = Image.open(r'C:\Python26\Suite\test.png')

        print im.format, im.size, im.mode

        im = ImageDraw.Draw(im)

        im = im.point((0, 0), fill="red")

        self.i = ImageTk.PhotoImage(im)
        self.ImbImage.create_image(139, 59, image=self.i)




def run():
    image_manip().mainloop()
if __name__ == "__main__":
    run()

Я получаю следующую ошибку при запуске моего кода:

Exception AttributeError: "PhotoImage instance has no attribute '_PhotoImage__photo'" in <bound method PhotoImage.__del__ of <PIL.ImageTk.PhotoImage instance at 0x05DF7698>> ignored
Traceback (most recent call last):
  File "<string>", line 245, in run_nodebug
  File "C:\Python26\Suite\test_image.py", line 30, in <module>
    run()
  File "C:\Python26\Suite\test_image.py", line 28, in run
    image_manip().mainloop()
  File "C:\Python26\Suite\test_image.py", line 20, in __init__
    self.i = ImageTk.PhotoImage(im)
  File "C:\Python26\lib\site-packages\PIL\ImageTk.py", line 109, in __init__
    mode = Image.getmodebase(mode)
  File "C:\Python26\lib\site-packages\PIL\Image.py", line 245, in getmodebase
    return ImageMode.getmode(mode).basemode
  File "C:\Python26\lib\site-packages\PIL\ImageMode.py", line 50, in getmode
    return _modes[mode]
KeyError: None

1 Ответ

9 голосов
/ 31 января 2011

Ваша проблема в том, что вы переназначаете im на несколько вещей.

im = Image.open(r'C:\Python26\Suite\test.png')
im = ImageDraw.Draw(im)
im = im.point((0, 0), fill="red")

Когда вы вызываете ImageTk.PhotoImage(im), функция ожидает объект изображения PIL, но вы уже присвоили imк результату функции point(), которая фактически возвращает None.Это причина вашей проблемы.

Я думаю, вы неправильно понимаете, как работает ImageDraw.Посмотрите здесь для примера.В основном:

  • Вам нужен экземпляр ImageDraw, если вы хотите нарисовать что-то сложное на вашем изображении PIL
  • Вам все еще нужно сохранить ваше изображение PIL в некоторой переменной
  • ImageDraw рисует непосредственно на изображении, которое вы дали во время строительства
  • Вы можете выбросить ImageDraw объект в любой точке.Он не содержит никакой важной информации, потому что все записано непосредственно на изображение.

Вот фиксированный метод __init__:

def __init__(self):
    Tkinter.Tk.__init__(self)
    self.configure(bg='red')
    im = Image.open(r'C:\Python26\Suite\test.png')
    width, height = im.size
    self.ImbImage = Tkinter.Canvas(self, highlightthickness=0, bd=0, bg='red', width=width, height=height)
    self.ImbImage.pack()
    print im.format, im.size, im.mode

    draw = ImageDraw.Draw(im)
    draw.rectangle([0, 0, 40, 40 ],  fill="green")
    del draw

    self.i = ImageTk.PhotoImage(im)
    self.ImbImage.create_image(width/2, height/2, image=self.i)

Вы заметите, что яисправлено несколько вещей:

  • Установите размер холста в соответствии с размером изображения.Очевидно, вам нужно загрузить изображение, прежде чем вы сможете найти его размер, поэтому я немного переместил его.
  • Назначьте экземпляр ImageDraw отдельной переменной
  • Нарисуйтезеленый прямоугольник вместо точки, потому что это будет выделяться больше.Обратите внимание, что вам не нужно захватывать возвращаемое значение draw.rectangle - оно фактически возвращает None, как это делают большинство других функций рисования.
  • Удалите переменную draw после того, как мы закончим рисование
  • Центрирование изображения на холсте при вызове create_image
...