3

我正在尝试使用PIL的ImageDraw模块进行单独的像素操作。下面的代码应该创建Tkinter画布部件。然后打开图像,将一个像素的颜色更改为红色,然后将图像嵌入到画布窗口小部件中。但是,它似乎并没有工作。使用PIL的ImageDraw模块

我的代码:

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 

回答

7

你的问题是你要重新分配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图像对象,但你已经分配impoint()功能,这实际上返回None的结果。这是你的问题的原因。

我认为你误解了ImageDraw的工作原理。例如,看看here。基本上是:

  • 如果你想画的东西复杂化你的PIL图片
  • 您仍然需要直接在图像你”上保持你的PIL图像中一些变量
  • ImageDraw油漆你需​​要的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
+0

感谢的时候,真的茅塞顿开绘制

  • 中心在画布后的图像。 – rectangletangle 2011-01-31 20:42:59