Python GTK resizing large image to fit inside a window - python

Important note: I'm using PyGObject to get access to the GTK widgets, not PyGTK. That's what makes this question different from similar ones:
PyGTK: How do I make an image automatically scale to fit it's parent widget?
Scale an image in GTK
I want to make a very simple app that displays a label, an image and a button, all stacked on top of each other. The app should be running in fullscreen mode.
When I attempted it, I've run into a problem. My image is of very high resolution, so when I simply create it from file and add it, I can barely see 20% of it.
What I want is for this image to be scaled by width according to the size of the window (which is equal to the screen size as the app runs in fullscreen).
I've tried using Pixbufs, but calling scale_simple on them didn't seem to change much.
Here's my current code:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf
class Window(Gtk.Window):
def __init__(self):
super().__init__(title='My app')
layout = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
dimensions = layout.get_allocation()
pixbuf = GdkPixbuf.Pixbuf.new_from_file('path/to/image')
pixbuf.scale_simple(dimensions.width, dimensions.height, GdkPixbuf.InterpType.BILINEAR)
image = Gtk.Image.new_from_pixbuf(pixbuf)
dismiss_btn = Gtk.Button(label='Button')
dismiss_btn.connect('clicked', Gtk.main_quit)
layout.add(image)
layout.add(dismiss_btn)
self.add(layout)
win = Window()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

The problem is that scale_simple actually returns a new Pixbuf, as per GTK+ docs.
Getting screen dimensions can be done by calling .get_screen() on the window and then calling .width() or .height() on the screen object.
The whole code put together looks something like this:
screen = self.get_screen()
pixbuf = GdkPixbuf.Pixbuf.new_from_file('/path/to/image')
pixbuf = pixbuf.scale_simple(screen.width(), screen.height() * 0.9, GdkPixbuf.InterpType.BILINEAR)
image = Gtk.Image.new_from_pixbuf(pixbuf)

Related

QWidget's grab method doesn't work on a QVTKRenderWindowInteractor object

Using pyqt (Python3.7, on Ubuntu 18.04), I've created a GUI in which I render some VTK stuff that I want to create a video of. Therefore, I need to Qwidget.grab() the main window and save it to a png file (so I can assemble the images to a video file).
This works fine for everything on the window (include QWidgets like sliders, combobox, etc. and matplotlib images) except for the rendered VTK object (QVTKRenderWindowInteractor) as it replaces it in the picture into a black box or sometime white noise.
I've made a minimal example of the problem, hoping that it was the complexity of the whole program that was the main problem. Unfortunately, even for minimal code, it still does not render the VTK part of the window.
Here is a minimal example of my problem, where clicking on the "Print" button should grab the image and save it to a PNG file.
import sys
from PyQt5.QtWidgets import QVBoxLayout,QPushButton, QWidget, QApplication
import vtk
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
def print_screen_callback(w):
w.grab().save("non_satisfying_printed_window.png")
# Create a small interface that show a cylinder and allow to print it to a PNG file
app = QApplication(sys.argv)
w = QWidget()
w.show()
lay = QVBoxLayout()
w.setLayout(lay)
# Create and populate the vtk widget
ren = vtk.vtkRenderer()
w_vtk = QVTKRenderWindowInteractor()
lay.addWidget(w_vtk)
w_vtk.Initialize()
w_vtk.Start()
w_vtk.GetRenderWindow().AddRenderer(ren)
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(8)
cylinderMapper = vtk.vtkPolyDataMapper()
cylinderMapper.SetInputConnection(cylinder.GetOutputPort())
cylinderActor = vtk.vtkActor()
cylinderActor.SetMapper(cylinderMapper)
ren.AddActor(cylinderActor)
# Add print screen button
but = QPushButton("Print")
lay.addWidget(but)
but.released.connect(lambda: print_screen_callback(w))
# Run the application
app.exec()
The expected output is of course the actual window when the person presses on the button "Print".

select certain monitor for going fullscreen with gtk

I intend to change the monitor where I show a fullscreen window.
This is especially interesting when having a projector hooked up.
I've tried to use fullscreen_on_monitor but that doesn't produce any visible changes.
Here is a non-working example:
#!/usr/bin/env python
import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
w = Gtk.Window()
screen = Gdk.Screen.get_default()
print ("Montors: %d" % screen.get_n_monitors())
if len(sys.argv) > 1:
n = int(sys.argv[1])
else:
n = 0
l = Gtk.Button(label="Hello, %d monitors!" % screen.get_n_monitors())
w.add(l)
w.show_all()
w.fullscreen_on_monitor(screen, n)
l.connect("clicked", Gtk.main_quit)
w.connect("destroy", Gtk.main_quit)
Gtk.main()
I get to see the window on the very same monitor (out of 3), regardless of the value I provide.
My question is: how do I make the fullscreen window appear on a different monitor?
The problem seems to be that Gtk just ignores the monitor number, it will always fullscreen the window on the monitor on which the window currently is positioned. This sucks, but we can use that to make it work the way we want to.
But first some theory about multiple monitors, they aren't actually separate monitors for your pc. It considers them to collectively form one screen which share the same global origin. On that global screen each monitor has a origin relative to the global origin, just like windows.
Because we know that Gtk will always fullscreen on the monitor on which the window is we can simply move the window to the origin of the monitor using window.move(x,y) and then call window.fullscreen().
(The move function will move the window to a position (x,y) relative to it's parent, which in the case of the main window is the global screen.)
Combining all this we get this, which works perfectly on Windows 10:
def fullscreen_at_monitor(window, n):
screen = Gdk.Screen.get_default()
monitor_n_geo = screen.get_monitor_geometry(n)
x = monitor_n_geo.x
y = monitor_n_geo.y
window.move(x,y)
window.fullscreen()
Here is an updated version of #B8vrede's answer, because get_monitor_geometry is deprecated since 3.22.
def fullscreen_at_monitor(window, n):
display = Gdk.Display.get_default()
monitor = Gdk.Display.get_monitor(display, n)
geometry = monitor.get_geometry()
x = geometry.x
y = geometry.y
window.move(x,y)
window.fullscreen()

PyQt4 - QWidget save as image

I'm trying to use Python to programmatically save a QWidget in PyQt4 as an image (any format would be fine - PNG, PDF, JPEF, GIF...etc)
I thought this would be very straightforward, but I actually wasn't able to find anything on the web about it. Can someone point me in the right direction?
To be clear, I'm trying to do this
gui = <SOME QMainWindow>
gui.show() # this displays the gui. it's useful, but what i need is to save the image
gui.save("image.png") ## How do I do this?
You can do this using the QPixmap.grabWindow() method.
From the docs:
Grabs the contents of the window window and makes a pixmap out of it.
Returns the pixmap.
The arguments (x, y) specify the offset in the window, whereas (w, h)
specify the width and height of the area to be copied.
If w is negative, the function copies everything to the right border
of the window. If h is negative, the function copies everything to the
bottom of the window.
Note that grabWindow() grabs pixels from the screen, not from the
window. If there is another window partially or entirely over the one
you grab, you get pixels from the overlying window, too.
Note also that the mouse cursor is generally not grabbed.
The reason we use a window identifier and not a QWidget is to enable
grabbing of windows that are not part of the application, window
system frames, and so on.
Warning: Grabbing an area outside the screen is not safe in general.
This depends on the underlying window system.
Warning: X11 only: If window is not the same depth as the root window
and another window partially or entirely obscures the one you grab,
you will not get pixels from the overlying window. The contests of the
obscured areas in the pixmap are undefined and uninitialized.
Sample code:
import sys
from PyQt4.QtGui import *
filename = 'Screenshot.jpg'
app = QApplication(sys.argv)
widget = QWidget()
widget.setLayout(QVBoxLayout())
label = QLabel()
widget.layout().addWidget(label)
def take_screenshot():
p = QPixmap.grabWindow(widget.winId())
p.save(filename, 'jpg')
widget.layout().addWidget(QPushButton('take screenshot', clicked=take_screenshot))
widget.show()
app.exec_()
This will produce a window that looks like this:
When you click the button, it will create a file named Screenshot.jpg in the current directory. Said image will look like this (notice the window frame is missing):

Gtk3 Image full window image from file (python3)

I need to find a way to load a image from file such that the image is actual size. I have read documentation [here][https://lazka.github.io/pgi-docs/Gtk-3.0] and [here][http://python-gtk-3-tutorial.readthedocs.org/en/latest/index.html] but the only way that seems to work is using the builder class to load a gui designed in glade. However via code I came up with the following and this does not produce the desired result, image is clipped.
from gi.repository import Gtk
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title='GMouse 600')
self.layout = Gtk.Layout.new(None,None)
self.add(self.layout)
self.background = Gtk.Image.new_from_file('./images/g600-thumb-buttons.jpg')
self.layout.put(self.background, 0, 0)
window = MainWindow()
window.connect('delete-event', Gtk.main_quit)
window.show_all()
Gtk.main()
I’m trying to find out how I can do this via code, in such a way that my image is filling the window. Can someone please provide any suggestions or possible solutions that I can try.
Note that the reason I wish to do this via code is when I use glade it does produce the desired result except when I try to add a grid layout on top of the image, or any other widget, it will not allow me. Also coding it will give me a chance to better learn and my gui is rather small, very few widgets will be used.
It seems I have solved the problem with the following code using Gtk.Overlay
from gi.repository import Gtk
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title='GMouse 600')
self.overlay = Gtk.Overlay()
self.add(self.overlay)
self.background = Gtk.Image.new_from_file('./images/g600-thumb-buttons.jpg')
self.overlay.add(self.background)
self.grid = Gtk.Grid()
self.button = Gtk.Button(label='Test')
self.grid.add(self.button)
self.overlay.add_overlay(self.grid)
window = MainWindow()
window.connect('delete-event', Gtk.main_quit)
window.show_all()
Gtk.main()

How do I include an image in a window with pygtk?

I'm trying to make a program in python which creates a fullscreen window and includes an image, but I don't really know how to do that. I've tried to read documentations on pygtk and I've searched in both goodle and stackoverflow, without any success.
Here's my current code.
def __init__(self):
pixbuf = gtk.gdk.pixbuf_new_from_file("test.png")
image = gtk.Image()
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.fullscreen()
self.window.show()
image.set_from_pixbuf(pixbuf)
image.show()
Question: how do I include an image in a window?
Please provide a little more context (e.g. class definition, imports).
Do not forget to add the image object to your window (before showing image and window):
self.window.add(image)
The tutorial example adds the image to a button, but you can try adding it directly to the main window:
# an image widget to contain the pixmap
image = gtk.Image()
image.set_from_pixmap(pixmap, mask)
image.show()
# a button to contain the image widget
button = gtk.Button()
button.add(image)
window.add(button)
button.show()
button.connect("clicked", self.button_clicked)

Categories