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
Related
I am writing a python program that gradually changes an image step by step, adjusting each pixel by a small amount in each step. To get a visualization of what the program is doing during runtime, I want it to display the image at each step, always overwriting the currently shown image so that it doesen't open bunch of display windows.
I already tried matplotlib, opencv and skimage, with their according possibilities to display an image and update the frame content in the course of the program:
# using scimage
viewer = ImageViewer(image)
viewer.show(main_window=False) # set the parameter to false so that the code doesn't block here but continues computation
..other code..
viewer.update_image(new_image)
# using matplotlib
myplot = plt.imshow(image)
plt.show(block=False)
.. other code..
myplot.set_data(new_image)
plt.show()
# using opencv
cv2.imshow('image',image)
.. other code ..
cv2.imshow('image', new_image)
I always ran into the problem that when it was supposed to open a frame with an image, it did not display the image but only a black screen. Weirdly enough, when I ran the code in IntelliJ in debug-mode and hit a breakpoint after the display-function, it worked.
What can I do so that it is displayed correctly when running the program normally and not with a breakpoint?
Here's the thing, I think your program does work, except it does and finishes unless you tell it to pause, which is why your breakpoint strategy is working.
Try pausing after showing image -
You can ask for user input. It'll pause until you enter some input to the program.
Put the program thread to sleep for some specified amount of time. This'll freeze your program for some given specified time, but you'll be able to see the image if it's already rendered.
Edit -
Since opencv's waitKey method is working for you now, you can use this method again to prevent the program from closing image window. Use waitKey(0) as your last program statement. It waits for a key press indefinitely, and returns the pressed key's code. Press any key to continue (but remember to have your image window in focus or it won't work), and your program should close if it's used in the end.
Also, I've striked earlier suggested options for pausing a program, because I'm unsure if it would've helped. I think waitKey method is more complex, and helps pause the program without freezing it.
Well, I am still not sure what exactly your goal is but here is a code piece that modifies an image inside of a window whenever the upper button is pressed.
from tkinter import Tk, Canvas, Button, Label, PhotoImage, mainloop
import random
WIDTH, HEIGHT = 800, 600
def modify_image():
print ("modifiying image...")
for x in range(1000):
img.put ( '#%06x' % random.randint(0, 16777215), # 6 char hex color
( random.randint(0, WIDTH), random.randint(0, HEIGHT) ) # (x, y)
)
canvas.update_idletasks()
print ("done")
canvas = Canvas(Tk(), width=WIDTH, height=HEIGHT, bg="#000000")
canvas.pack()
Button(canvas,text="modifiying image",command=modify_image).pack()
img = PhotoImage(width=WIDTH, height=HEIGHT)
Label(canvas,image=img).pack()
mainloop()
The function modify_image() adds 1000 random pixels to the image within the main window. Note the tkinter module is a default python module.
I'm using a zip file with a bunch of jpg files to show an animation because loading a gif file is too slow. I'd like to change the current screen if an animation reaches the end. How do I know if Image is still playing the animation? Is there any better way than setting a timer based on the animation's fps?
I am not aware of any way to capture that information. but here is an ugly hack.
If you set anim_loop to non zero for the Image and add a loop_count and an on_texture callback like this:
Image:
loop_count: 0
source: 'elephant.zip'
anim_delay: 0.05
anim_loop: 1
on_texture: app.on_texture(self)
Then an on_texture() method in the App can determine if the animation has completed:
def on_texture(self, img):
if img._coreimage.anim_index + 1 == len(img._coreimage.image.textures):
# one animation loop complete
img.loop_count += 1
if img.loop_count == img.anim_loop:
print('animation complete')
I can create an animated GIF like this:
from wand.image import Image
with Image() as im:
while i_need_to_add_more_frames():
im.sequence.append(Image(blob=get_frame_data(), format='png'))
with im.sequence[-1] as frame:
frame.delay = calculate_how_long_this_frame_should_be_visible()
im.type = 'optimize'
im.format = 'gif'
do_something_with(im.make_blob())
However, an image created like this loops indefinitely. This time, I want it to loop once, and then stop. I know that I could use convert's -loop parameter if I were using the commandline interface. However, I was unable to find how to do this using the Wand API.
What method should I call, or what field should I set, to make the generated GIF loop exactly once?
You'll need to use ctypes to bind the wand library to the correct C-API method.
Luckily this is straightforward.
import ctypes
from wand.image import Image
from wand.api import library
# Tell Python about the C-API method.
library.MagickSetImageIterations.argtypes = (ctypes.c_void_p, ctypes.c_size_t)
with Image() as im:
while i_need_to_add_more_frames():
im.sequence.append(Image(blob=get_frame_data(), format='png'))
with im.sequence[-1] as frame:
frame.delay = calculate_how_long_this_frame_should_be_visible()
im.type = 'optimize'
im.format = 'gif'
# Set the total iterations of the animation.
library.MagickSetImageIterations(im.wand, 1)
do_something_with(im.make_blob())
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.
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.