使用PIL的ImageDraw模块 [英] Using PIL's ImageDraw Module
问题描述
我正在尝试使用PIL的ImageDraw模块进行单独的像素操作。下面的代码应该创建Tkinter canvas小部件。然后打开图像,将一个像素的颜色更改为红色,然后将图像嵌入到画布小部件中。但是,它似乎没有用。
I'm trying to do individual pixel manipulation using PIL's ImageDraw Module. The code bellow is supposed to create Tkinter canvas widget. Then open an image, change one pixel's color to red, then embed the image in the canvas widget. However, it doesn't seem to be working.
我的代码:
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()
我在runni时遇到以下错误我的代码:
I get the following error upon running my code:
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
推荐答案
你的问题是你将 im
重新分配给多件事。
Your problem is you're reassigning im
to multiple things.
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()的结果
函数,实际返回无
。这是导致问题的原因。
When you call ImageTk.PhotoImage(im)
, the function expects a PIL image object, but you've already assigned im
to the result of the point()
function, which actually returns None
. This is the cause of your problem.
我认为你误解了ImageDraw的工作原理。有关示例,请查看此处。基本上:
I think you're misunderstanding how ImageDraw works. Have a look here for an example. Basically:
- 如果你想画一些复杂的东西,你需要一个
ImageDraw
的实例在您的PIL图片上 - 您仍然需要将PIL图像保存在某个变量中
-
ImageDraw
直接在施工期间给出的图像上绘画 - 您可以随时丢弃
ImageDraw
对象。它不包含任何重要信息,因为所有内容都直接写入图像。
- You need an instance of
ImageDraw
if you want to draw something complicated on your PIL Image - You still need to keep your PIL image in some variable
ImageDraw
paints directly on the image you've given it during construction time- You can throw away the
ImageDraw
object at any point. It doesn't contain any important information because everything is written directly to the image.
这是固定的 __ 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)
你会注意到我修了几件事:
You'll notice I've fixed a couple of things:
- 将画布大小设置为图像的大小。显然,你需要在找到图像大小之前加载图像,所以我已经移动了一些东西。
- 分配
ImageDraw
实例到单独的变量 - 绘制一个绿色矩形而不是一个点,因为这会更突出。请注意,您不需要获取
draw.rectangle
的返回值 - 它实际上返回无
,因为大多数其他绘图功能可以。 - 完成绘图后删除
draw
变量 - 调用
create_image
- Set the canvas size to the size of the image. Obviously, you need to load the image before you can find the image size, so I've moved things around a bit.
- Assign the
ImageDraw
instance to a separate variable - Draw a green rectangle instead of a dot, cause this will stand out more. Note you don't need to grab the return value of
draw.rectangle
-- it actually returnsNone
, as most other drawing functions do. - Delete the
draw
variable after we're done drawing - Center the image in the canvas when calling
create_image
这篇关于使用PIL的ImageDraw模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!