Python skull stamp mysteriously disappears after manipulating turtle image

Orientation:

I created the following functions, allowing the user to change the turtle to an image of their choice, and then stamp it on the canvas at any point:

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() 

The image can also be manipulated by the user by selecting the following functions:

Resize function . This function works either as a first or secondary function. The first means that it is called initially, and the secondary - edits an already edited image. Thus, if ONLY is called first, this function will take the image added to the pictures deque, resize it and output the edited image as a .gif image, which will become the new turtle shape. However, if you call two or more times in a row, due to a problem where resizing the same image more than once will result in a distorted image, I had to create another deque jiop that saves the original element from the pictures deque, and any the time this function is called more than once in a row, this original image changes every time, instead of the same image every time. But, if ONLY called a secondary function, then the function will simply output the current image from the edited deque, resize that image, and then set it as the new turtle shape:

 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() 

Functions flip, rotate and mirror . They work much easier than the resize function above. If they are called initially, each of them will take an image with pictures deque, process it, add the edited image to deque edited , and then change the โ€œshapeโ€ of the turtle to this new image. However, if they are called secondly, each of them will take the image with the edited deque, manipulate it, add the processed image back to the edited deque again, and then set it as the new "shape" of the turtle. These features are shown below:

 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() 

Thus, ALL editing functions work together essentially with the same main image.

Problem:

Now think that the user wants to take the image of the turtle, and then resize it to a size, for example, 800x400, and mark it in a specific place on the canvas. After that, the user decides to move the image of the turtle to another place on the canvas, flip the image and then print the image. Should there now be two images? One stamp and another rolled over? However, for some reason this is not the case with my program . . Instead, the stamped image disappears when the user flips the turtle image, even if there is no clear() function anywhere (to show what I mean, refer to edit below). Obviously, this problem ONLY occurs after the TurtleImageResize function is TurtleImageResize .

What is wrong with my TurtleImageResize function that leads to this problem? I completely updated the process of managing images of the turtle to understand what it is now, in the hope that it will fix this problem, that I also tested my previous setup, but, apparently, this is not so. Therefore, any help in this matter is greatly appreciated!

EDIT: The following is a minimal, complete, and verifiable way to reproduce the problem I am facing (MUST have PIL (or Pillow) and GhostScript for this to work) :

 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 

If / if both GhostScript and PIL (or pillow) are installed on your system, to reproduce my problem, follow these steps (all steps are required , except for step No. 4):

  • Click the Set Turtle Image button at the bottom of the window, select any image you want to make a turtle, and then click Open . The turtle gets this image.

  • Resize the image to 800x400 (or any other size) by clicking the Resize turtle Image button at the bottom of the screen. Two dialogs will appear. In the first dialog box, enter a width of 800 (or your own width), and then enter a height of 400 (or your own height) in the second dialog box, and after you finish, the image will resize to fit the dimensions provided (or set the image back to initial measurement (dimensions) depending on whether you click cancel).

  • Select the Stamp button at the bottom of the window. The image is applied to the canvas, and the turtle moves forward 400 pixels โ€œbehindโ€ the stamped image.

  • OPTIONAL: click anywhere on the canvas to take the turtle to this place.

  • Flip / Mirror / Rotate Image.

As you can see, after doing all this, just as you flip / flip the image, the stamped image just disappears. What is wrong with my TurtleImageResize function that calls this?

EDIT # 2: Just in case this information is useful, I am running Python 3.5.1 on Macintosh with OS version 10.11.2 (El Capitan).

+5
source share
1 answer

The problem is that having separate counters for different functions, you overwrite files created by previous operations. Say you have an image called test.gif and apply a flip transformation. The result will be saved as test.gif1.gif . If you now apply rotary transform, the rotated image is also saved as test.gif1.gif , overwriting the existing file, and the previous image disappears.

Thus, one way to fix this error is to use one counter for all images instead of one function, for example. using itertools.count or just int . It will also make your code a little shorter.


However, there are a few more issues that I would like to point out:

  • you have a lot of code duplication, especially in your various conversion functions; you can reorganize those who accept the actual transformation as a function parameter
  • do not do except: as much as less than except: pass ; that way, you never know what happened in case something goes wrong.
  • In addition, IMHO exceptions should only be used for exceptional behavior, while you use them for normal behavior, such as when lists are still empty.
  • I really don't see what all these different queue ; the code works just as well if you put all the images in one queue or don't queue at all (just saving them to disk); but maybe you need those that were not part of your sample code.

Here is my version of the code:

 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() 
+4
source

Source: https://habr.com/ru/post/1241288/


All Articles