Given two images with the same size, I'm trying to transform one into another, but with several frames in between them.
My idea of workflow is something like:
retrieve pixel matrix from images:
img1_pixels = img1.load()
img2_pixels = img2.load()
and create a frame like:
for y in range(11):
x = 10 - y
frame = (x*0.1)*img1_pixels + (y*0.1)*img2_pixels
frame.show()
time.sleep(1)
I've read some stuff and I know is recommended to use tkinter instead of pil since show() is just for debugging.
The problem is that I can't find an example in which tkinter and pil are used to display a set of frames in order to generate an animation.
I can make it work if I bind the update to a keystroke. At the moment I use time.sleep the script freezes.
Does anyone have an example or a suggestion of a good way to do it?
Thank you,
Lucas.
Related
I currently have a listbox with the paths of dozens of images, when an element in the listbox is selected the image will be displayed in the middle of the gui.
My third image has 2 different looks to it so i wrote:
#Third image
elif (self.index==3):
start = clock()
self.label.configure(image=self.photo2[1])#first image
if (start>2):
self.label.configure(image=self.photo2[2])#second image
For now when the user clicks the third element it will first display the first image, then if reclicked after two seconds it will display the second image, so that works.
However, what I want is for my third image to automatically change after two seconds without reclicking. Is there a way to update an image live in tkinter or any ideas on what approach I could take?
This is a common pattern. You should use Tk.after to run a function that changes the image then schedules the next change.
def change_image(label, imagelist, nextindex):
label.configure(image=imagelist[nextindex])
root.after(2000, lambda: change_image(label, imagelist, (nextindex+1) % len(imagelist)))
Then call it once and let it do its thing forever.
root = Tk()
setup_your_stuff()
change_image(root.label, root.photo2, 0)
I have this little python script which opens up a window and puts an animated GIF inside the window. I'm using it as a screensaver (nothing fancy, really). My problem is that the GIF isn't the size of my monitor; it's quite small on the screen. What I'd like to do is to scale it to the size of the screen. I have looked into PIL as well as images2gif, but they don't give me the scaling options I require.
What I would like to do is load the animated GIF in the script, then scale it, and finally play in the window generated by PyGTK. What I've tried doing is using subprocess to capture the output from gifsicle. While this does scale the GIF I can't use it in the PyGTK part of the script because of the data returned from subprocess. What I do is:
p = subprocess.check_output(["gifsicle --scale 3.3 foo.gif"], shell=True)
The variable p has the animated GIF data, but I can't use with PyGTK in that condition. Ideally I would like to load it like this:
pixbufAn = gtk.gdk.pixbufAnimation(p)
image = gtk.Image()
image.set_from_animation(pixbufAn)
Is there a way for me to use the data from the gifsicle --scale 3.3 foo.gif call? Or is there a pure Python way of scaling the animated GIF and using it with PyGTK?
logically you can use
GdkPixbuf.Pixbuf.scale_simple ()
on all the GdkPixbuf contains within GdkPixbuf.PixbufAnimation. How to get the single GdkPixbuf.Pixbuf? Use the iter to walk through GdkPixbuf.PixbufAnimation. first iter would be
iter = GdkPixbuf.PixbufAnimation.get_iter (GLib.get_current_time() )
pbuf = iter.get_pixbuf ()
# scale the pbuf below
......
# make this on a loop
iter = iter.advance (GLib.get_current_time())
# after getting all the pbuf, pack again into GdkPixbuf.PixbufSimpleAnim
simpleanim = GdkPixbuf.PixbufSimpleAnim (width, height, rate)
# loop again
simpleanim.add_frame (pbuf)
# after done all the chores, call the
Gtk.Image.set_from_animation (simpleanim) #simpleanim implemented anim
I am currently remaking flappy bird in Tkinter. (I understand this is bad, I explain why at the bottom.) My issue is with the pipes, and the speeds they scroll at and the distance they are from each other. Unless something is wrong with my logic, if a start the two pipes separated from each other then move them when they get to a certain point, and place them at the same point, they should retain the gap between them. This may be better explained in code.
from tkinter import *
import random
root = Tk()
root.geometry('430x640')
root.configure(background='turquoise')
canvas = Canvas(root,width=int(435),height=int(645))
canvas.configure(background='turquoise')
canvas.pack()
x, x2 = 400, 700
y = random.randint(0,300)
y2 = random.randint(0,300)
def drawPipe():
global x,x2,y,y2
canvas.coords(pipeTop,(x,0,(x+50),y))
canvas.coords(pipeBottom,(x,640,(x+50),(y+150)))
canvas.coords(pipeTop2,(x2,0,(x2+50),y2))
canvas.coords(pipeBottom2,(x2,640,(x2+50),(y2+150)))
x -= 3
x2 -= 3
if x < -46:
x = 435
y = random.randint(5,540)
if x2 <-46:
x2 = 435
y2 = random.randint(5,540)
root.after(1,drawPipe)
pipeTop = canvas.create_rectangle(x,0,(x+50),y,fill='green')
pipeBottom = canvas.create_rectangle(x,640,x+50,y+150,fill='green')
pipeTop2 = canvas.create_rectangle(x2,0,(x2+50),y,fill='green')
pipeBottom2 = canvas.create_rectangle(x2,640,(x2+50),(y2+150),fill='green')
drawPipe()
root.mainloop()
This is not my full code, but it is the bit concerned with drawing and updating the pipes. When run, this code will show you how the pipes scrolling speed up and down. I do not understand how this is possible. All the values for the pipes are the same apart from the starting positions. Is this due to the inefficient way Tkinter uses the after method? I attempted to use threading but this produced problems when using root.bind (see my previous question). Or is it due to a logic error? Thank you in advance to anyone who can help me.
Side note: I realise I should not be making a game in tkinter, especially one that requires multiple things to be happening at once. However, I am doing this at school and the modules I would like to use (Pygame or Pyglet) cannot be downloaded just for me to make a game that has no real purpose. If I could use something other than tkinter I probably would. Thank you for your help.
Using after(1,..) you get 1000FPS (Frames Per Second) but you don't need it - use after(20, ...) to get 50 FPS.
Beside using after(1,..) your program have no time to do other things - it have no time to execute all after() so you can get different speed.
With after(1,..) I couldn't even move window.
And my CPU became hotter so fan started working faster and louder.
I'm quite new to Python and have been unsuccessful in finding a way around this problem. I have a GUI using TKinter that displays an image using Label. I would like the user to be able to click on two places in the image and use those two pixel locations elsewhere.
Below is the basic code I'm using so far, but I'm unable to return the pixel locations. I believe bind is not what I want to use, is there another option?
px = []
py = []
def onmouse(event):
px.append(event.x)
py.append(event.y)
return px,py
self.ImgPanel.bind('<button-1>',onmouse)
If I try to use:
px,py = self.ImgPanel.bind('<button-1>',onmouse)
I get an error "Too many values to unpack"
bind is what you want, if you want to capture the x,y coordinate of the click. However, functions called from bindings don't "return". Technically they do, but they return a value to the internals of Tkinter.
What you need to do is set an instance or global variable within the bound function. In the code you included in your question, if you add global px,py, you can then use those values in other code.
First of all, it is important to mention that I'm learning Python and Gtk+ 3, so I'm not an advanced programmer in these languages.
I'm trying to make a graphical interface in Gtk3 for a Python script that creates a png image, and I'd like to display it, but the PyGobject documentation is so scarce that I haven't found a way to do that. So far, my interface looks like this:
The buttons and text entries are arranged in a grid, and I'd like to keep empty the big space (represented by the big button) to the right until the script finishes building the image, and then show it in that area. The code is here.
Is there a way to do that using Python in Gtk3?
Thanks in advance,
Germán.
EDIT
Taking a look at the demos pointed out by #gpoo I discovered the Frame widget, and I implemented it in my GUI. This is how it looks like:
Inside the window class, I add the Frame to the grid:
self.frame_rgb = Gtk.Frame(label='RGB image')
self.frame_rgb.set_label_align(0.5, 0.5)
self.frame_rgb.set_shadow_type(Gtk.ShadowType.IN)
self.grid.attach_next_to(self.frame_rgb, self.label_img_name,
Gtk.PositionType.RIGHT, 3, 8)
I also connect the Run button to a callback function, so that when I click on it, my script creates and then displays the png image:
self.button_run = Gtk.Button(stock=Gtk.STOCK_EXECUTE)
self.button_run.connect('clicked', self.on_button_run_clicked)
self.grid.attach_next_to(self.button_run, self.entry_b_img,
Gtk.PositionType.BOTTOM, 1, 1)
Finally, my callback function is (no calculations yet, only render the image to the Frame for testing purposes):
def on_button_run_clicked(self, widget):
self.img = Gtk.Image.new_from_file('astro-tux.png')
self.frame_rgb.add(self.img)
but I got the following error when I click the Run button:
(makeRGB.py:2613): Gtk-WARNING **: Attempting to add a widget with
type GtkImage to a GtkFrame, but as a GtkBin subclass a GtkFrame can
only contain one widget at a time; it already contains a widget of
type GtkImage
Any help is appreciated!
You can use Gtk.Image. If you generate a file, you could use:
img = Gtk.Image.new_from_file('/path/to/my_file.png')
and add img to the container (GtkGrid in your case). Or, if you already have the Gtk.Image there, you can use:
img.set_from_file('/path/to/my_file.png')
Instead of ...from_file you can use from_pixbuf, and you can create a Gdk.Pixbuf from a stream.
In general, you can use the documentation for C and change the idiom to Python. Also, you can check the demos available in PyGObject, in particular, the demo for handling images.