Python 海龟形状图像处理后海龟图章神秘消失
Python turtle stamp mysteriously disappears after turtle shape's image manipulation
方向:
我创建了以下函数,允许用户将乌龟更改为 his/her 选择的图像,然后在任何时候将其标记为 canvas:
def TurtleShape():
try:
# Tkinter buttons related to turtle manipulation
manipulateimage.config(state = NORMAL)
flipButton.config(state = NORMAL)
mirrorButton.config(state = NORMAL)
originalButton.config(state = NORMAL)
resetturtle.config(state = NORMAL)
rotateButton.config(state = NORMAL)
# Ask user for file name from tkinter file dialog, and return file name as `klob`
global klob
klob = filedialog.askopenfilename()
global im
# Open `klob` and return as `im`
im = Image.open(klob)
# Append `im` to pictures deque
pictures.append(im)
# Clear `edited` deque
edited.clear()
# Save `im` as an image, then register image as shape, and finally set image as turtle shape
im.save(klob + '.gif', "GIF")
register_shape(klob + '.gif')
shape(klob + '.gif')
update()
except:
# If user selects cancel in file dialog, then pass
pass
def StampPic():
stamp()
draw_space() # Go forward 100 pixels with pen up after every stamp
update()
图像也可以通过这些其他函数根据用户的选择进行操作:
Resize function – 此功能可作为第一功能或辅助功能使用。第一个意思是它最初被调用,第二个意思是它编辑一个已经编辑过的图像。因此,如果仅首先调用,此函数将获取附加到 pictures
双端队列的图像,调整其大小,并将编辑后的图像输出为 .gif
图像,这将是海龟的新形状。但是,如果连续调用两次或更多次,由于多次调整同一张图片的大小会导致图像失真,我不得不创建另一个双端队列 jiop
来保存 pictures
deque,每当连续多次调用此函数时,每次都会调整原始图像的大小,而不是每次都调整相同的图像。但是,如果仅作为辅助函数调用,那么该函数将简单地从 edited
双端队列中获取当前图像,调整该图像的大小,然后将其设置为海龟的新形状:
def TurtleImageResize():
if not hasattr(TurtleImageResize, "counter"):
TurtleImageResize.counter = 0
TurtleImageResize.counter += 1
# width = original size of image
width = im.size[0]
# height = original height of image
height = im.size[1]
# Allow user to enter new width for image
NewOne2 = numinput('Width of Image', 'Set the width of the image: ', minval = 1)
# Allow user to enter new height for image
NewOne = numinput('Height of Image', 'Set the height of your image: ', minval = 1)
# Set width to user input if user input is NOT nothing. Otherwise, use `width` as picture width.
Picwidth = NewOne2 if NewOne2 != None else width
# Set height to user input if user input is NOT None. Otherwise, use `height` as picture height.
Picheight = NewOne if NewOne != None else height
try:
# Secondary Step: Take ORIGINAL image appended to `jiop` (from `except:` code block succeeding `try:` code block) and resize THAT image each time this function is called twice in a row. Otherwise, if ONLY called as a secondary step, take previously edited image from `edited` deque, resize that, and append newly edited image to the `edited` deque.
try:
# `jiop` is a deque
hye = jiop.pop()
jiop.append(hye)
print("Jiop")
except:
hye = edited.pop()
jiop.append(hye)
print("Edited")
# Resize Image to Picwidth and Picheight
editpic = hye.resize((int(Picwidth), int(Picheight)), Image.ANTIALIAS)
edited.append(editpic)
print("Hooplah!")
except:
# Intial step: Take image appended to `pictures` deque from `TurtleShape` function, then edit that and append newly edited image to both `editpic` and `pictures`
geer = pictures.pop()
# Resize Image to Picwidth and Picheight
editpic = geer.resize((int(Picwidth), int(Picheight)), Image.ANTIALIAS)
jiop.append(geer)
edited.append(editpic)
pictures.append(editpic)
print("Normal")
# Save image as `.gif`
editpic.save(klob + str(TurtleImageResize.counter) + '.gif', 'GIF')
# Register image as a shape, and use it as shape of turtle
register_shape(klob + str(TurtleImageResize.counter) + '.gif')
shape(klob + str(TurtleImageResize.counter) + '.gif')
update()
翻转、旋转和镜像函数 - 这些函数比上面的调整大小函数更简单。如果最初被调用,他们每个人将从 pictures
双端队列获取图像,对其进行操作,将编辑后的图像附加到 edited
双端队列,然后将乌龟 "shape" 更改为该新图像。但是,如果调用第二个,它们每个人将从 edited
双端队列中获取图像,对其进行操作,将操作后的图像重新附加回 edited
双端队列,然后将其设置为海龟的新 "shape".这些函数如下所示:
def flippic():
if not hasattr(flippic, "counter"):
flippic.counter = 0
flippic.counter += 1
try:
# Secondary step: Take previously edited image from `edited` deque, manipulate that, and append newly edited image to the `edited` deque
jiop.clear()
ghy = edited.pop()
# Flip image over horizontal line
kpl = ImageOps.flip(ghy)
edited.append(kpl)
print("Jlop")
except:
# Initial step: Take image appended to `pictures` deque from `TurtleShape` function, then edit that and append newly edited image to both `editpic` and `pictures`
neer = pictures.pop()
# Flip image over horizontal line
kpl = ImageOps.flip(neer)
pictures.append(kpl)
edited.append(kpl)
print("Yup")
# Save image as `.gif`
kpl.save(klob + str(flippic.counter) + '.gif', "GIF")
# Register image as a shape, and use it as shape of turtle
register_shape(klob + str(flippic.counter) + '.gif')
shape(klob + str(flippic.counter) + '.gif')
update()
def mirror():
if not hasattr(mirror, "counter"):
mirror.counter = 0
mirror.counter += 1
try:
jiop.clear()
jui = edited.pop()
# Flip image over vertical line
fgrt = ImageOps.mirror(jui)
edited.append(fgrt)
except:
bbc = pictures.pop()
# Flip image over vertical line
fgrt = ImageOps.mirror(bbc)
pictures.append(fgrt)
edited.append(fgrt)
fgrt.save(klob + str(mirror.counter) + ".gif")
register_shape(klob + str(mirror.counter) + ".gif")
shape(klob + str(mirror.counter) + ".gif")
update()
def rotatePic():
if not hasattr(rotatePic, "counter"):
rotatePic.counter = 0
rotatePic.counter += 1
try:
jiop.clear()
lmcb = edited.pop()
# Rotate image 90º right
fetch = lmcb.rotate(-90, expand = True)
edited.append(fetch)
except:
bolt = pictures.pop()
# Rotate image 90º right
fetch = bolt.rotate(-90, expand = True)
pictures.append(fetch)
edited.append(fetch)
fetch.save(klob + str(rotatePic.counter) + ".gif")
register_shape(klob + str(rotatePic.counter) + ".gif")
shape(klob + str(rotatePic.counter) + ".gif")
update()
这样所有的编辑功能都可以在基本相同的基本图像上协同工作。
问题:
现在,假设用户想要拍摄海龟图像,然后将其调整为大小,例如 800x400,并将其标记到 canvas 上的特定位置。之后,用户决定将海龟图像移动到 canvas 上的另一个位置,翻转图像,然后将图像标记在那里。现在应该有两个图像吧?一个盖章,另一个翻转?但是,对于我的程序,出于某种原因,情况并非如此。相反,标记图像 在用户翻转海龟图像时消失 ,即使在任何地方都找不到 clear()
函数(为了向您展示我的意思,请参阅编辑)。 显然,此问题仅在调用 TurtleImageResize
函数后发生。
我的 TurtleImageResize
函数有什么问题导致了这个问题? 我已经将海龟形状的图像管理过程完全改造成现在的样子希望它能解决我在之前的设置中也遇到的这个问题,但显然,情况仍然不是这样。因此,非常感谢任何对此问题的帮助!
编辑: 下面是重现我遇到的问题的最小、完整且可验证的方法(必须安装 PIL(或 Pillow)和 GhostScript
才能正常工作):
import os,shutil,subprocess, sys
her = sys.platform
if her == "win32":
print("Windows is your Operating System")
win_gs = ["gs","gswin32c","gswin64c"]
if all( shutil.which(gs_version) is None for gs_version in win_gs ):
paths = ["C:\Program Files\gs\gs9.18\bin","C:\Program Files (x86)\gs\gs9.18\bin"]
for path in (x for x in paths if os.path.exists(x)):
os.environ["PATH"] += ";" + path
break
if any( shutil.which(gs_version) for gs_version in win_gs ):
print("GhostScript 9.18 for Windows found and utilized")
else:
print("You do not have GhostScript 9.18 installed for Windows. Please install it.")
sys.exit(0)
else:
print("GhostScript 9.18 for Windows found and utilized")
elif her == 'darwin':
print("Macintosh is your Operating System")
if shutil.which("gs") is None:
os.environ["PATH"] += ":/usr/local/bin"
if shutil.which("gs") is None:
print("You do not have GhostScript installed for Macintosh. Please install it.")
sys.exit(0)
else:
print("GhostScript for Macintosh found and utilized")
from turtle import *
from tkinter import *
try:
import tkinter.filedialog as filedialog
except ImportError:
pass
import collections
from PIL import Image, ImageEnhance, ImageOps
jiop = collections.deque()
pictures = collections.deque()
edited = collections.deque()
picwidth = collections.deque()
picheight = collections.deque()
def draw_space():
# Draw a space 200 pixels wide.
penup()
forward(200)
pendown()
def TurtleShape():
try:
manipulateimage.config(state = NORMAL)
flipButton.config(state = NORMAL)
mirrorButton.config(state = NORMAL)
rotateButton.config(state = NORMAL)
global klob
klob = filedialog.askopenfilename()
global im
im = Image.open(klob)
pictures.append(im)
edited.clear()
im.save(klob + '.gif', "GIF")
register_shape(klob + '.gif')
shape(klob + '.gif')
update()
except AttributeError:
pass
def TurtleImageResize():
if not hasattr(TurtleImageResize, "counter"):
TurtleImageResize.counter = 0
TurtleImageResize.counter += 1
width = im.size[0]
height = im.size[1]
NewOne2 = numinput('Width of Image', 'Set the width of the image: ', minval = 1)
NewOne = numinput('Height of Image', 'Set the height of your image: ', minval = 1)
Picwidth = NewOne2 if NewOne2 != None else width
picwidth.append(Picwidth)
Picheight = NewOne if NewOne != None else height
picheight.append(Picheight)
try:
try:
hye = jiop.pop()
jiop.append(hye)
except:
hye = edited.pop()
jiop.append(hye)
editpic = hye.resize((int(Picwidth), int(Picheight)), Image.ANTIALIAS)
edited.append(editpic)
pictures.append(editpic)
except:
geer = pictures.pop()
editpic = geer.resize((int(Picwidth), int(Picheight)), Image.ANTIALIAS)
jiop.append(geer)
edited.append(editpic)
pictures.append(editpic)
editpic.save(klob + str(TurtleImageResize.counter) + '.gif', 'GIF')
register_shape(klob + str(TurtleImageResize.counter) + '.gif')
shape(klob + str(TurtleImageResize.counter) + '.gif')
update()
def flippic():
if not hasattr(flippic, "counter"):
flippic.counter = 0
flippic.counter += 1
try:
jiop.clear()
ghy = edited.pop()
kpl = ImageOps.flip(ghy)
edited.append(kpl)
pictures.append(kpl)
print("Jlop")
except:
neer = pictures.pop()
kpl = ImageOps.flip(neer)
pictures.append(kpl)
edited.append(kpl)
print("Yup")
kpl.save(klob + str(flippic.counter) + '.gif', "GIF")
register_shape(klob + str(flippic.counter) + '.gif')
shape(klob + str(flippic.counter) + '.gif')
update()
def mirror():
if not hasattr(mirror, "counter"):
mirror.counter = 0
mirror.counter += 1
try:
jiop.clear()
jui = edited.pop()
fgrt = ImageOps.mirror(jui)
edited.append(fgrt)
pictures.append(fgrt)
except:
bbc = pictures.pop()
fgrt = ImageOps.mirror(bbc)
pictures.append(fgrt)
edited.append(fgrt)
fgrt.save(klob + str(mirror.counter) + ".gif")
register_shape(klob + str(mirror.counter) + ".gif")
shape(klob + str(mirror.counter) + ".gif")
update()
def rotatePic():
if not hasattr(rotatePic, "counter"):
rotatePic.counter = 0
rotatePic.counter += 1
try:
jiop.clear()
lmcb = edited.pop()
fetch = lmcb.rotate(-90, expand = True)
edited.append(fetch)
pictures.append(fetch)
except:
bolt = pictures.pop()
fetch = bolt.rotate(-90, expand = True)
pictures.append(fetch)
edited.append(fetch)
fetch.save(klob + str(rotatePic.counter) + ".gif")
register_shape(klob + str(rotatePic.counter) + ".gif")
shape(klob + str(rotatePic.counter) + ".gif")
update()
def StampPic():
stamp()
draw_space()
update()
def move_turtle():
# Pick up the turtle and move it to its starting location.
penup()
goto(-200, 100)
pendown()
def settings():
# Tkinter buttons
turtlepic = Button(text = "Set Turtle Image", command = TurtleShape)
turtlepic.pack(side = 'left')
stampimage = Button(text = "Stamp", command = StampPic)
stampimage.pack(side = 'left')
global manipulateimage
manipulateimage = Button(text = "Resize Turtle Image", command = TurtleImageResize, state = DISABLED)
manipulateimage.pack(side = 'left')
global flipButton
flipButton = Button(text = "Flip image", command = flippic, state = DISABLED)
flipButton.pack(side = 'left')
global mirrorButton
mirrorButton = Button(text = "Mirror Image", command = mirror, state = DISABLED)
mirrorButton.pack(side = 'left')
global rotateButton
rotateButton = Button(text = "Rotate Image", command = rotatePic, state = DISABLED)
rotateButton.pack(side = 'left')
def skip(x, y):
penup()
goto(x, y)
pendown()
update()
move_turtle()
settings()
speed(0)
tracer(0, 0)
onscreenclick(skip)
if sys.platform == 'win32':
input()
else:
pass
When/if 您的系统上同时安装了 GhostScript
和 PIL(或 Pillow),要重现我的问题,请执行以下操作(所有步骤 需要 除了 步骤 # 4):
单击 window 底部的 Set Turtle Image
按钮,select 任何您想要乌龟的图像,然后按 Open
。海龟被设置为该图像。
按屏幕底部的 Resize turtle Image
按钮将图像调整为 800x400(或您想要的任何其他尺寸)。将连续弹出两个对话框。在第一个对话框中输入宽度800(或你自己的宽度),然后在第二个对话框中输入高度400(或你自己的高度),完成后,图像会根据提供的尺寸改变大小(或根据您是否按下取消将图像设置回原始尺寸)。
Select window 底部的 Stamp
按钮。图像被标记到 canvas 上,海龟向前移动 400 像素 "behind" 标记图像。
可选:单击 canvas 上的任意位置将乌龟带到该位置。
Flip/mirror/rotate 图片。
如您所见,完成所有这些操作后,就在您 flip/mirror/rotate 图像时,标记的图像 消失了 。 我的 TurtleImageResize
函数有什么问题导致出现这种情况?
EDIT # 2: 以防万一此信息有用,我是 运行 Python Macintosh 上的 3.5.1 OS 版本 10.11.2 (El Capitan)。
问题似乎是,通过为不同的函数设置单独的计数器,您覆盖了之前操作创建的文件。假设您有一张名为 test.gif
的图片并应用了翻转转换。结果将保存为 test.gif1.gif
。如果现在应用旋转变换,旋转后的图片也保存为test.gif1.gif
,覆盖现有文件,之前的图片消失
所以修复这个错误的一种方法是对所有图片使用一个计数器,而不是每个函数一个,例如使用 itertools.count
或仅使用 int
。这也会使您的代码更短一些。
不过,我还想指出几个问题:
- 你有相当多的代码重复,尤其是在你不同的转换函数中;您可以重构这些以将实际转换作为函数参数
- 不要
except:
那么多,更不要except: pass
;这样你就永远不会知道发生了什么事,以防出现问题
- 此外,恕我直言,异常应该只用于异常行为,而您将它们用于正常行为,例如当列表仍然为空时
- 我真的不明白那些不同的
queue
是干什么用的;如果将所有图片放入一个队列,或者根本没有队列(只是将它们保存在磁盘上),代码也能正常工作;但也许你需要那些不属于你的示例代码的东西
这是我的代码版本:
import turtle
import tkinter
import tkinter.filedialog as filedialog
import itertools
from PIL import Image, ImageEnhance, ImageOps
count = itertools.count()
img = None
def turtleShape():
global img
klob = filedialog.askopenfilename()
img = Image.open(klob)
saveAndUpdate(img)
def turtleImageResize():
def resize(img):
picwidth = turtle.numinput('Width of Image', 'Set the width of the image: ', minval=1) or img.size[0]
picheight = turtle.numinput('Height of Image', 'Set the height of your image: ', minval=1) or img.size[1]
return img.resize((int(picwidth), int(picheight)), Image.ANTIALIAS)
manipulate(resize)
def manipulate(function):
global img
if img:
img = function(img)
saveAndUpdate(img)
else:
print("No picture selected")
def flippic():
manipulate(ImageOps.flip)
def mirror():
manipulate(ImageOps.mirror)
def rotatePic():
manipulate(lambda img: img.rotate(-90, expand=True))
def saveAndUpdate(img):
name = "pic_" + str(next(count)) + ".gif"
img.save(name, 'GIF')
turtle.register_shape(name)
turtle.shape(name)
turtle.update()
def stampPic():
turtle.stamp()
turtle.penup()
turtle.forward(200)
turtle.pendown()
def settings():
tkinter.Button(text="Set Turtle Image", command=turtleShape).pack(side='left')
tkinter.Button(text="Stamp", command=stampPic).pack(side = 'left')
tkinter.Button(text="Resize Turtle Image", command=turtleImageResize).pack(side='left')
tkinter.Button(text="Flip image", command=flippic).pack(side='left')
tkinter.Button(text="Mirror Image", command=mirror).pack(side='left')
tkinter.Button(text="Rotate Image", command=rotatePic).pack(side='left')
def skip(x, y):
turtle.penup()
turtle.goto(x, y)
turtle.pendown()
turtle.update()
skip(-200, 100)
settings()
turtle.speed(0)
turtle.tracer(0, 0)
turtle.onscreenclick(skip)
turtle.mainloop()
方向:
我创建了以下函数,允许用户将乌龟更改为 his/her 选择的图像,然后在任何时候将其标记为 canvas:
def TurtleShape():
try:
# Tkinter buttons related to turtle manipulation
manipulateimage.config(state = NORMAL)
flipButton.config(state = NORMAL)
mirrorButton.config(state = NORMAL)
originalButton.config(state = NORMAL)
resetturtle.config(state = NORMAL)
rotateButton.config(state = NORMAL)
# Ask user for file name from tkinter file dialog, and return file name as `klob`
global klob
klob = filedialog.askopenfilename()
global im
# Open `klob` and return as `im`
im = Image.open(klob)
# Append `im` to pictures deque
pictures.append(im)
# Clear `edited` deque
edited.clear()
# Save `im` as an image, then register image as shape, and finally set image as turtle shape
im.save(klob + '.gif', "GIF")
register_shape(klob + '.gif')
shape(klob + '.gif')
update()
except:
# If user selects cancel in file dialog, then pass
pass
def StampPic():
stamp()
draw_space() # Go forward 100 pixels with pen up after every stamp
update()
图像也可以通过这些其他函数根据用户的选择进行操作:
Resize function – 此功能可作为第一功能或辅助功能使用。第一个意思是它最初被调用,第二个意思是它编辑一个已经编辑过的图像。因此,如果仅首先调用,此函数将获取附加到 pictures
双端队列的图像,调整其大小,并将编辑后的图像输出为 .gif
图像,这将是海龟的新形状。但是,如果连续调用两次或更多次,由于多次调整同一张图片的大小会导致图像失真,我不得不创建另一个双端队列 jiop
来保存 pictures
deque,每当连续多次调用此函数时,每次都会调整原始图像的大小,而不是每次都调整相同的图像。但是,如果仅作为辅助函数调用,那么该函数将简单地从 edited
双端队列中获取当前图像,调整该图像的大小,然后将其设置为海龟的新形状:
def TurtleImageResize():
if not hasattr(TurtleImageResize, "counter"):
TurtleImageResize.counter = 0
TurtleImageResize.counter += 1
# width = original size of image
width = im.size[0]
# height = original height of image
height = im.size[1]
# Allow user to enter new width for image
NewOne2 = numinput('Width of Image', 'Set the width of the image: ', minval = 1)
# Allow user to enter new height for image
NewOne = numinput('Height of Image', 'Set the height of your image: ', minval = 1)
# Set width to user input if user input is NOT nothing. Otherwise, use `width` as picture width.
Picwidth = NewOne2 if NewOne2 != None else width
# Set height to user input if user input is NOT None. Otherwise, use `height` as picture height.
Picheight = NewOne if NewOne != None else height
try:
# Secondary Step: Take ORIGINAL image appended to `jiop` (from `except:` code block succeeding `try:` code block) and resize THAT image each time this function is called twice in a row. Otherwise, if ONLY called as a secondary step, take previously edited image from `edited` deque, resize that, and append newly edited image to the `edited` deque.
try:
# `jiop` is a deque
hye = jiop.pop()
jiop.append(hye)
print("Jiop")
except:
hye = edited.pop()
jiop.append(hye)
print("Edited")
# Resize Image to Picwidth and Picheight
editpic = hye.resize((int(Picwidth), int(Picheight)), Image.ANTIALIAS)
edited.append(editpic)
print("Hooplah!")
except:
# Intial step: Take image appended to `pictures` deque from `TurtleShape` function, then edit that and append newly edited image to both `editpic` and `pictures`
geer = pictures.pop()
# Resize Image to Picwidth and Picheight
editpic = geer.resize((int(Picwidth), int(Picheight)), Image.ANTIALIAS)
jiop.append(geer)
edited.append(editpic)
pictures.append(editpic)
print("Normal")
# Save image as `.gif`
editpic.save(klob + str(TurtleImageResize.counter) + '.gif', 'GIF')
# Register image as a shape, and use it as shape of turtle
register_shape(klob + str(TurtleImageResize.counter) + '.gif')
shape(klob + str(TurtleImageResize.counter) + '.gif')
update()
翻转、旋转和镜像函数 - 这些函数比上面的调整大小函数更简单。如果最初被调用,他们每个人将从 pictures
双端队列获取图像,对其进行操作,将编辑后的图像附加到 edited
双端队列,然后将乌龟 "shape" 更改为该新图像。但是,如果调用第二个,它们每个人将从 edited
双端队列中获取图像,对其进行操作,将操作后的图像重新附加回 edited
双端队列,然后将其设置为海龟的新 "shape".这些函数如下所示:
def flippic():
if not hasattr(flippic, "counter"):
flippic.counter = 0
flippic.counter += 1
try:
# Secondary step: Take previously edited image from `edited` deque, manipulate that, and append newly edited image to the `edited` deque
jiop.clear()
ghy = edited.pop()
# Flip image over horizontal line
kpl = ImageOps.flip(ghy)
edited.append(kpl)
print("Jlop")
except:
# Initial step: Take image appended to `pictures` deque from `TurtleShape` function, then edit that and append newly edited image to both `editpic` and `pictures`
neer = pictures.pop()
# Flip image over horizontal line
kpl = ImageOps.flip(neer)
pictures.append(kpl)
edited.append(kpl)
print("Yup")
# Save image as `.gif`
kpl.save(klob + str(flippic.counter) + '.gif', "GIF")
# Register image as a shape, and use it as shape of turtle
register_shape(klob + str(flippic.counter) + '.gif')
shape(klob + str(flippic.counter) + '.gif')
update()
def mirror():
if not hasattr(mirror, "counter"):
mirror.counter = 0
mirror.counter += 1
try:
jiop.clear()
jui = edited.pop()
# Flip image over vertical line
fgrt = ImageOps.mirror(jui)
edited.append(fgrt)
except:
bbc = pictures.pop()
# Flip image over vertical line
fgrt = ImageOps.mirror(bbc)
pictures.append(fgrt)
edited.append(fgrt)
fgrt.save(klob + str(mirror.counter) + ".gif")
register_shape(klob + str(mirror.counter) + ".gif")
shape(klob + str(mirror.counter) + ".gif")
update()
def rotatePic():
if not hasattr(rotatePic, "counter"):
rotatePic.counter = 0
rotatePic.counter += 1
try:
jiop.clear()
lmcb = edited.pop()
# Rotate image 90º right
fetch = lmcb.rotate(-90, expand = True)
edited.append(fetch)
except:
bolt = pictures.pop()
# Rotate image 90º right
fetch = bolt.rotate(-90, expand = True)
pictures.append(fetch)
edited.append(fetch)
fetch.save(klob + str(rotatePic.counter) + ".gif")
register_shape(klob + str(rotatePic.counter) + ".gif")
shape(klob + str(rotatePic.counter) + ".gif")
update()
这样所有的编辑功能都可以在基本相同的基本图像上协同工作。
问题:
现在,假设用户想要拍摄海龟图像,然后将其调整为大小,例如 800x400,并将其标记到 canvas 上的特定位置。之后,用户决定将海龟图像移动到 canvas 上的另一个位置,翻转图像,然后将图像标记在那里。现在应该有两个图像吧?一个盖章,另一个翻转?但是,对于我的程序,出于某种原因,情况并非如此。相反,标记图像 在用户翻转海龟图像时消失 ,即使在任何地方都找不到 clear()
函数(为了向您展示我的意思,请参阅编辑)。 显然,此问题仅在调用 TurtleImageResize
函数后发生。
我的 TurtleImageResize
函数有什么问题导致了这个问题? 我已经将海龟形状的图像管理过程完全改造成现在的样子希望它能解决我在之前的设置中也遇到的这个问题,但显然,情况仍然不是这样。因此,非常感谢任何对此问题的帮助!
编辑: 下面是重现我遇到的问题的最小、完整且可验证的方法(必须安装 PIL(或 Pillow)和 GhostScript
才能正常工作):
import os,shutil,subprocess, sys
her = sys.platform
if her == "win32":
print("Windows is your Operating System")
win_gs = ["gs","gswin32c","gswin64c"]
if all( shutil.which(gs_version) is None for gs_version in win_gs ):
paths = ["C:\Program Files\gs\gs9.18\bin","C:\Program Files (x86)\gs\gs9.18\bin"]
for path in (x for x in paths if os.path.exists(x)):
os.environ["PATH"] += ";" + path
break
if any( shutil.which(gs_version) for gs_version in win_gs ):
print("GhostScript 9.18 for Windows found and utilized")
else:
print("You do not have GhostScript 9.18 installed for Windows. Please install it.")
sys.exit(0)
else:
print("GhostScript 9.18 for Windows found and utilized")
elif her == 'darwin':
print("Macintosh is your Operating System")
if shutil.which("gs") is None:
os.environ["PATH"] += ":/usr/local/bin"
if shutil.which("gs") is None:
print("You do not have GhostScript installed for Macintosh. Please install it.")
sys.exit(0)
else:
print("GhostScript for Macintosh found and utilized")
from turtle import *
from tkinter import *
try:
import tkinter.filedialog as filedialog
except ImportError:
pass
import collections
from PIL import Image, ImageEnhance, ImageOps
jiop = collections.deque()
pictures = collections.deque()
edited = collections.deque()
picwidth = collections.deque()
picheight = collections.deque()
def draw_space():
# Draw a space 200 pixels wide.
penup()
forward(200)
pendown()
def TurtleShape():
try:
manipulateimage.config(state = NORMAL)
flipButton.config(state = NORMAL)
mirrorButton.config(state = NORMAL)
rotateButton.config(state = NORMAL)
global klob
klob = filedialog.askopenfilename()
global im
im = Image.open(klob)
pictures.append(im)
edited.clear()
im.save(klob + '.gif', "GIF")
register_shape(klob + '.gif')
shape(klob + '.gif')
update()
except AttributeError:
pass
def TurtleImageResize():
if not hasattr(TurtleImageResize, "counter"):
TurtleImageResize.counter = 0
TurtleImageResize.counter += 1
width = im.size[0]
height = im.size[1]
NewOne2 = numinput('Width of Image', 'Set the width of the image: ', minval = 1)
NewOne = numinput('Height of Image', 'Set the height of your image: ', minval = 1)
Picwidth = NewOne2 if NewOne2 != None else width
picwidth.append(Picwidth)
Picheight = NewOne if NewOne != None else height
picheight.append(Picheight)
try:
try:
hye = jiop.pop()
jiop.append(hye)
except:
hye = edited.pop()
jiop.append(hye)
editpic = hye.resize((int(Picwidth), int(Picheight)), Image.ANTIALIAS)
edited.append(editpic)
pictures.append(editpic)
except:
geer = pictures.pop()
editpic = geer.resize((int(Picwidth), int(Picheight)), Image.ANTIALIAS)
jiop.append(geer)
edited.append(editpic)
pictures.append(editpic)
editpic.save(klob + str(TurtleImageResize.counter) + '.gif', 'GIF')
register_shape(klob + str(TurtleImageResize.counter) + '.gif')
shape(klob + str(TurtleImageResize.counter) + '.gif')
update()
def flippic():
if not hasattr(flippic, "counter"):
flippic.counter = 0
flippic.counter += 1
try:
jiop.clear()
ghy = edited.pop()
kpl = ImageOps.flip(ghy)
edited.append(kpl)
pictures.append(kpl)
print("Jlop")
except:
neer = pictures.pop()
kpl = ImageOps.flip(neer)
pictures.append(kpl)
edited.append(kpl)
print("Yup")
kpl.save(klob + str(flippic.counter) + '.gif', "GIF")
register_shape(klob + str(flippic.counter) + '.gif')
shape(klob + str(flippic.counter) + '.gif')
update()
def mirror():
if not hasattr(mirror, "counter"):
mirror.counter = 0
mirror.counter += 1
try:
jiop.clear()
jui = edited.pop()
fgrt = ImageOps.mirror(jui)
edited.append(fgrt)
pictures.append(fgrt)
except:
bbc = pictures.pop()
fgrt = ImageOps.mirror(bbc)
pictures.append(fgrt)
edited.append(fgrt)
fgrt.save(klob + str(mirror.counter) + ".gif")
register_shape(klob + str(mirror.counter) + ".gif")
shape(klob + str(mirror.counter) + ".gif")
update()
def rotatePic():
if not hasattr(rotatePic, "counter"):
rotatePic.counter = 0
rotatePic.counter += 1
try:
jiop.clear()
lmcb = edited.pop()
fetch = lmcb.rotate(-90, expand = True)
edited.append(fetch)
pictures.append(fetch)
except:
bolt = pictures.pop()
fetch = bolt.rotate(-90, expand = True)
pictures.append(fetch)
edited.append(fetch)
fetch.save(klob + str(rotatePic.counter) + ".gif")
register_shape(klob + str(rotatePic.counter) + ".gif")
shape(klob + str(rotatePic.counter) + ".gif")
update()
def StampPic():
stamp()
draw_space()
update()
def move_turtle():
# Pick up the turtle and move it to its starting location.
penup()
goto(-200, 100)
pendown()
def settings():
# Tkinter buttons
turtlepic = Button(text = "Set Turtle Image", command = TurtleShape)
turtlepic.pack(side = 'left')
stampimage = Button(text = "Stamp", command = StampPic)
stampimage.pack(side = 'left')
global manipulateimage
manipulateimage = Button(text = "Resize Turtle Image", command = TurtleImageResize, state = DISABLED)
manipulateimage.pack(side = 'left')
global flipButton
flipButton = Button(text = "Flip image", command = flippic, state = DISABLED)
flipButton.pack(side = 'left')
global mirrorButton
mirrorButton = Button(text = "Mirror Image", command = mirror, state = DISABLED)
mirrorButton.pack(side = 'left')
global rotateButton
rotateButton = Button(text = "Rotate Image", command = rotatePic, state = DISABLED)
rotateButton.pack(side = 'left')
def skip(x, y):
penup()
goto(x, y)
pendown()
update()
move_turtle()
settings()
speed(0)
tracer(0, 0)
onscreenclick(skip)
if sys.platform == 'win32':
input()
else:
pass
When/if 您的系统上同时安装了 GhostScript
和 PIL(或 Pillow),要重现我的问题,请执行以下操作(所有步骤 需要 除了 步骤 # 4):
单击 window 底部的
Set Turtle Image
按钮,select 任何您想要乌龟的图像,然后按Open
。海龟被设置为该图像。按屏幕底部的
Resize turtle Image
按钮将图像调整为 800x400(或您想要的任何其他尺寸)。将连续弹出两个对话框。在第一个对话框中输入宽度800(或你自己的宽度),然后在第二个对话框中输入高度400(或你自己的高度),完成后,图像会根据提供的尺寸改变大小(或根据您是否按下取消将图像设置回原始尺寸)。Select window 底部的
Stamp
按钮。图像被标记到 canvas 上,海龟向前移动 400 像素 "behind" 标记图像。可选:单击 canvas 上的任意位置将乌龟带到该位置。
Flip/mirror/rotate 图片。
如您所见,完成所有这些操作后,就在您 flip/mirror/rotate 图像时,标记的图像 消失了 。 我的 TurtleImageResize
函数有什么问题导致出现这种情况?
EDIT # 2: 以防万一此信息有用,我是 运行 Python Macintosh 上的 3.5.1 OS 版本 10.11.2 (El Capitan)。
问题似乎是,通过为不同的函数设置单独的计数器,您覆盖了之前操作创建的文件。假设您有一张名为 test.gif
的图片并应用了翻转转换。结果将保存为 test.gif1.gif
。如果现在应用旋转变换,旋转后的图片也保存为test.gif1.gif
,覆盖现有文件,之前的图片消失
所以修复这个错误的一种方法是对所有图片使用一个计数器,而不是每个函数一个,例如使用 itertools.count
或仅使用 int
。这也会使您的代码更短一些。
不过,我还想指出几个问题:
- 你有相当多的代码重复,尤其是在你不同的转换函数中;您可以重构这些以将实际转换作为函数参数
- 不要
except:
那么多,更不要except: pass
;这样你就永远不会知道发生了什么事,以防出现问题 - 此外,恕我直言,异常应该只用于异常行为,而您将它们用于正常行为,例如当列表仍然为空时
- 我真的不明白那些不同的
queue
是干什么用的;如果将所有图片放入一个队列,或者根本没有队列(只是将它们保存在磁盘上),代码也能正常工作;但也许你需要那些不属于你的示例代码的东西
这是我的代码版本:
import turtle
import tkinter
import tkinter.filedialog as filedialog
import itertools
from PIL import Image, ImageEnhance, ImageOps
count = itertools.count()
img = None
def turtleShape():
global img
klob = filedialog.askopenfilename()
img = Image.open(klob)
saveAndUpdate(img)
def turtleImageResize():
def resize(img):
picwidth = turtle.numinput('Width of Image', 'Set the width of the image: ', minval=1) or img.size[0]
picheight = turtle.numinput('Height of Image', 'Set the height of your image: ', minval=1) or img.size[1]
return img.resize((int(picwidth), int(picheight)), Image.ANTIALIAS)
manipulate(resize)
def manipulate(function):
global img
if img:
img = function(img)
saveAndUpdate(img)
else:
print("No picture selected")
def flippic():
manipulate(ImageOps.flip)
def mirror():
manipulate(ImageOps.mirror)
def rotatePic():
manipulate(lambda img: img.rotate(-90, expand=True))
def saveAndUpdate(img):
name = "pic_" + str(next(count)) + ".gif"
img.save(name, 'GIF')
turtle.register_shape(name)
turtle.shape(name)
turtle.update()
def stampPic():
turtle.stamp()
turtle.penup()
turtle.forward(200)
turtle.pendown()
def settings():
tkinter.Button(text="Set Turtle Image", command=turtleShape).pack(side='left')
tkinter.Button(text="Stamp", command=stampPic).pack(side = 'left')
tkinter.Button(text="Resize Turtle Image", command=turtleImageResize).pack(side='left')
tkinter.Button(text="Flip image", command=flippic).pack(side='left')
tkinter.Button(text="Mirror Image", command=mirror).pack(side='left')
tkinter.Button(text="Rotate Image", command=rotatePic).pack(side='left')
def skip(x, y):
turtle.penup()
turtle.goto(x, y)
turtle.pendown()
turtle.update()
skip(-200, 100)
settings()
turtle.speed(0)
turtle.tracer(0, 0)
turtle.onscreenclick(skip)
turtle.mainloop()