wxPython screenshot Windows - python

I've got an (apparently) cross-platform screenshot function using wxPython:
def take_screenshot(x=0, y=0, width=None, height=None):
try:
import wx
except ImportError as e:
return 'Screenshot could not be taken - wx could not be imported: %s' %(e)
import os, datetime
folder_name = datetime.date.today().strftime('%Y-%m-%d')
file_name = datetime.datetime.now().strftime('%H-%M-%S') + '.png'
directory = os.path.join(os.getcwd(), 'screenshots', folder_name)
make_directory(directory)
filename = os.path.join(directory, file_name)
app = wx.App()
screen = wx.ScreenDC()
size = screen.GetSize()
if width == None:
width = size[0]
if height == None:
height = size[1]
bmp = wx.EmptyBitmap(width, height)
mem = wx.MemoryDC(bmp)
mem.Blit(0, 0, width, height, screen, x, y)
del mem
bmp.SaveFile(filename, wx.BITMAP_TYPE_PNG)
return 'Screenshot saved to file: %s' %(filename)
Here is a screenshot I took on Windows 7. This code works fine on Linux. I'm running on Python 2.7.8 and wxPython 3.0.2.0
Has anyone seen any similar problems? Am I doing something wrong?

This was discussed a few years ago on Stack and the wxPython mailing list. At that time, there was no reliable cross-platform method of taking a screenshot of the user's screen. I have not heard of any improvements since. You might try the PyQt method mentioned in the Stack link or you could try out the pyscreenshot project.

Update for wxPython 4 and higher
import wx
app = wx.App(False)
screen = wx.ScreenDC()
size = screen.GetSize()
width = size.width
height = size.height
bmp = wx.Bitmap(width, height)
# Create a memory DC that will be used for actually taking the screenshot
memDC = wx.MemoryDC()
# Tell the memory DC to use our Bitmap
# all drawing action on the memory DC will go to the Bitmap now
memDC.SelectObject(bmp)
# Blit (in this case copy) the actual screen on the memory DC
memDC.Blit(
0, 0,
width, height,
screen,
0, 0
)
# Select the Bitmap out of the memory DC by selecting a new bitmap
memDC.SelectObject(wx.NullBitmap)
im = bmp.ConvertToImage()
im.SaveFile('screenshot.png', wx.BITMAP_TYPE_PNG)

Related

Multiple screenshots using ScreenDC, wxPython

I ran into a problem with ScreenDC in wxPython Phoenix.
My tool is supposed to take multiple screenshots with some period. But whenever I use ScreenDC to grab a screenshot and save it to PNG it works well only for the first time. All the following times it just saves the same image as the first one. To get a new image, I have to restart the program, which is not an option in my case. I guess that whenever I call wx.ScreenDC() it gets the same image as the first time.
Ubuntu 16.04, wxPython 3.0.3 gtk3, python 3.6
The code I used:
def take_screenshot():
screen = wx.ScreenDC()
size = screen.GetSize()
width = size[0]
height = size[1]
bmp = wx.Bitmap(width, height)
mem = wx.MemoryDC(bmp)
mem.Blit(0, 0, width, height, screen, 0, 0)
bmp.SaveFile(str(datetime.now()) + '.png', wx.BITMAP_TYPE_PNG)
if __name__ == '__main__':
app = wx.App()
take_screenshot()
sleep(3)
take_screenshot()
sleep(3)
take_screenshot()
sleep(3)
take_screenshot()
Maybe there is the way to clean that first image from memory.
The only solution I found is to run a separate process, define wx.App inside and then to perform the function. However, that is not an option for my program.
Thanks.
UPD: It seems to be some issue of wxPython Phoenix. If you run this on wxPython Classic, everything works fine(just use EmptyBitmap, not Bitmap). Weird, I will report this issue in their repository.
I was not able to reproduce your issue in Phoenix or Classic (on Windows). I suppose what could happen is that sleep blocks wxPython event loop. It would be good style to put long-running things in a separate thread anyway. It is painless, see below.
from threading import Thread
...
if __name__ == '__main__':
app = wx.App()
def payload():
take_screenshot()
sleep(3)
take_screenshot()
sleep(3)
take_screenshot()
sleep(3)
take_screenshot()
thrd = Thread(target=payload)
thrd.start()
EDIT: As the asker pointed out, there may be issues with thread-safety in the approach above. How does the thing work below for you (tested on Phoenix and Classic on Windows)?
from __future__ import print_function
import wx
from datetime import datetime
from time import sleep
IS_PHOENIX = True if 'phoenix' in wx.version() else False
if IS_PHOENIX:
EmptyBitmap = lambda *args, **kwds: wx.Bitmap(*args, **kwds)
else:
EmptyBitmap = lambda *args, **kwds: wx.EmptyBitmap(*args, **kwds)
def take_screenshot():
screen = wx.ScreenDC()
size = screen.GetSize()
width = size[0]
height = size[1]
bmp = EmptyBitmap(width, height)
mem = wx.MemoryDC(bmp)
mem.Blit(0, 0, width, height, screen, 0, 0)
bmp.SaveFile(str(datetime.now().second) + '.png', wx.BITMAP_TYPE_PNG)
MAXPICS = 4
class testfrm(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.tmr = wx.Timer(self, -1)
self.countpics = 0
self.Bind(wx.EVT_TIMER, self.ontimer, self.tmr)
self.ontimer(None)
def ontimer(self, evt):
if self.countpics <=MAXPICS:
self.tmr.Start(3000, wx.TIMER_ONE_SHOT)
take_screenshot()
self.countpics += 1
else:
self.Close()
if __name__ == '__main__':
app = wx.App()
frm = testfrm(None, -1, wx.version())
app.MainLoop()

How to do a screenshot of a tkinter application?

I need to do a screenshot of the content of the tkinter application below. I am on Windows 7 (or 8).
from Tkinter import *
def test(x):
#print "I'm in event:", x
if x == 1: # if event on entry e1
print 'e1 event' # do some thing
elif x == 2: # also if event on entry e2
print 'e2 event' # do some thing else
else:
print 'no event'
def test1(x):
test(1)
def test2(x):
test(2)
root=Tk()
root.minsize(500,500)
e1=Entry(root)
e1.pack()
e2=Entry(root)
e2.pack()
e1.bind( "<FocusOut>", test1)
e2.bind( "<FocusOut>", test2)
button=Button(root, text='print').pack(side=BOTTOM)
root.mainloop()
I made a module that takes screenshot of tkinter window.
You can install with: pip install tkcap
GitHub repository
Usage:
import tkcap
cap = tkcap.CAP(master) # master is an instance of tkinter.Tk
cap.capture(FileName) # Capture and Save the screenshot of the tkiner window
Since you mentioned that you are on Windows. You can use the Win32 API as directed in this answer Fastest way to take a screenshot with python on windows. Hope this helps.
But actually Pyscreenshot should be what you are looking for.
Take the following code for example:
from pyscreenshot import grab
im = grab(bbox=(100, 200, 300, 400))
im.show()
As you can see you can use bbox to take screenshot that is at co-ordinates (100, 200) and has a width of 300 and a height of 400.
Also as regards the printing check out Printing using win32api. I hope these help.
Using PIL you can do a resize:
from PIL import Image
from pyscreenshot import grab
img = grab(bbox=(100, 200, 300, 400))
# to keep the aspect ratio
w = 300
h = 400
maxheight = 600
maxwidth = 800
ratio = min(maxwidth/width, maxheight/height)
# correct image size is not #oldsize * ratio#
# img.resize(...) returns a resized image and does not effect img unless
# you assign the return value
img = img.resize((h * ratio, width * ratio), Image.ANTIALIAS)
I would advise changing your program so that you can resize the image before printing

HICON/HBITMAP to QIcon/QPixmap/QImage/Anything with a Q in it

I'm trying to get 48x48 or 256x256 icons from files in Windows and have come across what seems like a dead-end. At the moment I have a HICON handle(since PySides QFileIconProvider only returns 32x32 icons) in python which I would like to show in a pyside window but functions like QPixmap.fromHICON/HBITMAP are not implemented and also seems to have been removed from the source since Qt 4.8(?). Also, I'm trying to avoid having to save the icon to a file.
So, is there any way to get a HICON or possibly any other things you can turn it into, to any kind of PySide object?
EDIT:
I've been trying to simply rewrite the old function fromWinHBITMAP function in python but it isn't going great. I'm uncertain how I should translate the src line into python and I don't either have any idea how I change the value of the memory buffer returned by QImage.scanLine()
for (int y=0; y<h; ++y) {
QRgb *dest = (QRgb *) image.scanLine(y);
const QRgb *src = (const QRgb *) (data + y * bytes_per_line);
for (int x=0; x<w; ++x) {
dest[x] = src[x] | mask;
}
}
At the moment I create a PyCBITMAP from the HICON with the win32api and retrieves the list of bits.
for y in range(0, hIcon.height):
dest = i.scanLine(y)
src = bitmapbits[y*hIcon.widthBytes:(y*hIcon.widthBytes)+hIcon.widthBytes]
for x in range(0, hIcon.width):
dest[x] = bytes(ctypes.c_uint32(src[x] | 0))
This results in "ValueError: cannot modify size of memoryview object"
The source for the function be found here: http://www.qtcentre.org/threads/19188-Converting-from-HBitmap-to-a-QPixmap?p=94747#post94747
Fixed it!
def iconToQImage(hIcon):
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, hIcon.width, hIcon.height)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
win32gui.DrawIconEx(hdc.GetHandleOutput(), 0, 0, hIcon.hIcon, hIcon.width, hIcon.height, 0, None, 0x0003)
bitmapbits = hbmp.GetBitmapBits(True)
image = QtGui.QImage(bitmapbits, hIcon.width, hIcon.height, QtGui.QImage.Format_ARGB32_Premultiplied)
return image
It's a bit hard to get this sort of setup going but from I read around Python Imaging Library (PIL) supports bitmap and ICO files and has downloads for Windows. Assuming you can get a filename of the icon, you can load it up with PIL and then transfer the raw data to a QImage:
from PIL import Image
from PySide.QtGui import QImage, QImageReader, QLabel, QPixmap, QApplication
im = Image.open("my_image.png")
data = im.tostring('raw', 'RGBA')
app = QApplication([])
image = QImage(data, im.size[0], im.size[1], QImage.Format_ARGB32)
pix = QPixmap.fromImage(image)
lbl = QLabel()
lbl.setPixmap(pix)
lbl.show()
app.exec_()
Then work with whatever QImage operation you need to do from there.
While #egs0's answer is accurate, trying to display the output may cause problems because QLabel doesn't handle bitmap very well. To solve these problems, convert the result to another image format.
import win32ui
import win32gui
# Doesn't matter which library. Qt5 should work just as well.
from PySide6 import QtGui, QtCore
def iconToQImage(hIcon, width, height, im_format="PNG"):
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, width, height)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
win32gui.DrawIconEx(hdc.GetHandleOutput(), 0, 0, hIcon, width, height, 0, None, 0x0003)
bitmapbits = hbmp.GetBitmapBits(True)
image = QtGui.QImage(bitmapbits, width, height, QtGui.QImage.Format_ARGB32_Premultiplied)
# Write to and then load from a buffer to convert to PNG.
buffer = QtCore.QBuffer()
buffer.setOpenMode(QtCore.QIODevice.ReadWrite)
image.save(buffer, im_format)
image.loadFromData(buffer.data(), im_format)
# Use QtGui.Pixmap.fromImage() to get a pixmap instead.
return image
It's also possible to get the size of an icon using the following function, adapted from here:
def getIconSize(HIcon):
info = win32gui.GetIconInfo(HIcon)
if info[4]: # Icon has color plane.
bmp = win32gui.GetObject(info[4])
width = bmp.bmWidth
height = bmp.bmHeight
else: # Icon has no colour plane, image data stored in mask.
bmp = win32gui.GetObject(info[3])
width = bmp.width
height = bmp.height // 2 # A monochrome icon contains image and XOR mask in the hbmMask.
info[3].close()
info[4].close()
return width, height

Image resize under PhotoImage

I need to resize an image, but I want to avoid PIL, since I cannot make it work under OS X - don't ask me why...
Anyway since I am satisfied with gif/pgm/ppm, the PhotoImage class is ok for me:
photoImg = PhotoImage(file=imgfn)
images.append(photoImg)
text.image_create(INSERT, image=photoImg)
The problem is - how do I resize the image?
The following works only with PIL, which is the non-PIL equivalent?
img = Image.open(imgfn)
img = img.resize((w,h), Image.ANTIALIAS)
photoImg = ImageTk.PhotoImage(img)
images.append(photoImg)
text.image_create(INSERT, image=photoImg)
Thank you!
Because both zoom() and subsample() want integer as parameters, I used both.
I had to resize 320x320 image to 250x250, I ended up with
imgpath = '/path/to/img.png'
img = PhotoImage(file=imgpath)
img = img.zoom(25) #with 250, I ended up running out of memory
img = img.subsample(32) #mechanically, here it is adjusted to 32 instead of 320
panel = Label(root, image = img)
You have to either use the subsample() or the zoom() methods of the PhotoImage class. For the first option you first have to calculate the scale factors, simply explained in the following lines:
scale_w = new_width/old_width
scale_h = new_height/old_height
photoImg.zoom(scale_w, scale_h)
If you don't have PIL installed --> install it
(for Python3+ users --> use 'pip install pillow' in cmd)
from tkinter import *
import tkinter
import tkinter.messagebox
from PIL import Image
from PIL import ImageTk
master = Tk()
def callback():
print("click!")
width = 50
height = 50
img = Image.open("dir.png")
img = img.resize((width,height), Image.ANTIALIAS)
photoImg = ImageTk.PhotoImage(img)
b = Button(master,image=photoImg, command=callback, width=50)
b.pack()
mainloop()
I just had the same problem, and I found that #Memes' answer works rather well. Just make sure to reduce your ratio as much as possible, as subsample() takes a rather long time to run for some reason.
Basically, the image is zoomed out to the least common factor of the two sizes, and then being subsidized by the origonal size. This leaves you with the image of the desired size.
I had a requirement where I wanted to open an image, resize it, keeping the aspect ratio, save it under a new name, & display it in a tkinter window (using Linux Mint). After looking through dozens of forum questions, and dealing with some weird errors (semmingly involving the PIL to Pillow fork in Python 3.x), I was able to develop some code that works, using a predefined new maximum width or new maximum height (scaling up or down as necessary), and a Canvas object, where the image is displayed centered in the frame. Note that I did not include the file dialogs, just a hardcoded Image open & save for one file:
from tkinter import *
from PIL import ImageTk, Image
import shutil,os
from tkinter import filedialog as fd
maxwidth = 600
maxheight = 600
mainwindow = Tk()
picframe = Frame(mainwindow)
picframe.pack()
canvas = Canvas(picframe, width = maxwidth, height = maxheight)
canvas.pack()
img = Image.open("/home/user1/Pictures/abc.jpg")
width, height = img.size # Code to scale up or down as necessary to a given max height or width but keeping aspect ratio
if width > height:
scalingfactor = maxwidth/width
width = maxwidth
height = int(height*scalingfactor)
else:
scalingfactor = maxheight/height
height = maxheight
width = int(width*scalingfactor)
img = img.resize((width,height), Image.ANTIALIAS)
img.save("/home/user1/Pictures/Newabc.jpg")
img = ImageTk.PhotoImage(img) # Has to be after the resize
canvas.create_image(int(maxwidth/2)-int(width/2), int(maxheight/2)-int(height/2), anchor=NW, image=img) # No autocentering in frame, have to manually calculate with a new x, y coordinate based on a NW anchor (upper left)

How do I get monitor resolution in Python?

What is the simplest way to get monitor resolution (preferably in a tuple)?
I created a PyPI module for this reason:
pip install screeninfo
The code:
from screeninfo import get_monitors
for m in get_monitors():
print(str(m))
Result:
Monitor(x=3840, y=0, width=3840, height=2160, width_mm=1420, height_mm=800, name='HDMI-0', is_primary=False)
Monitor(x=0, y=0, width=3840, height=2160, width_mm=708, height_mm=399, name='DP-0', is_primary=True)
It supports multi monitor environments. Its goal is to be cross platform; for now it supports Cygwin and X11 but pull requests are totally welcome.
In Windows, you can also use ctypes with GetSystemMetrics():
import ctypes
user32 = ctypes.windll.user32
screensize = user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)
so that you don't need to install the pywin32 package;
it doesn't need anything that doesn't come with Python itself.
For multi-monitor setups, you can retrieve the combined width and height of the virtual monitor:
import ctypes
user32 = ctypes.windll.user32
screensize = user32.GetSystemMetrics(78), user32.GetSystemMetrics(79)
On Windows:
from win32api import GetSystemMetrics
print("Width =", GetSystemMetrics(0))
print("Height =", GetSystemMetrics(1))
If you are working with high resolution screen, make sure your python interpreter is HIGHDPIAWARE.
Based on this post.
Taken directly from an answer to the post How can I get the screen size in Tkinter?,
import tkinter as tk
root = tk.Tk()
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
If you're using wxWindows, you can simply do:
import wx
app = wx.App(False) # the wx.App object must be created first.
print(wx.GetDisplaySize()) # returns a tuple
On Windows 8.1 I am not getting the correct resolution from either ctypes or tk. Other people are having this same problem for ctypes: getsystemmetrics returns wrong screen size
To get the correct full resolution of a high DPI monitor on Windows 8.1, one must call SetProcessDPIAware and use the following code:
import ctypes
user32 = ctypes.windll.user32
user32.SetProcessDPIAware()
[w, h] = [user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)]
Full Details Below:
I found out that this is because windows is reporting a scaled resolution. It appears that python is by default a 'system dpi aware' application. Types of DPI aware applications are listed here:
High DPI Desktop Application Development on Windows
Basically, rather than displaying content the full monitor resolution, which would make fonts tiny, the content is scaled up until the fonts are big enough.
On my monitor I get:
Physical resolution: 2560 x 1440 (220 DPI)
Reported python resolution: 1555 x 875 (158 DPI)
Per this Windows site: Adjusting Scale for Higher DPI Screens.
The formula for reported system effective resolution is:
(reported_px*current_dpi)/(96 dpi) = physical_px
I'm able to get the correct full screen resolution, and current DPI with the below code.
Note that I call SetProcessDPIAware() to allow the program to see the real resolution.
import tkinter as tk
root = tk.Tk()
width_px = root.winfo_screenwidth()
height_px = root.winfo_screenheight()
width_mm = root.winfo_screenmmwidth()
height_mm = root.winfo_screenmmheight()
# 2.54 cm = in
width_in = width_mm / 25.4
height_in = height_mm / 25.4
width_dpi = width_px/width_in
height_dpi = height_px/height_in
print('Width: %i px, Height: %i px' % (width_px, height_px))
print('Width: %i mm, Height: %i mm' % (width_mm, height_mm))
print('Width: %f in, Height: %f in' % (width_in, height_in))
print('Width: %f dpi, Height: %f dpi' % (width_dpi, height_dpi))
import ctypes
user32 = ctypes.windll.user32
user32.SetProcessDPIAware()
[w, h] = [user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)]
print('Size is %f %f' % (w, h))
curr_dpi = w*96/width_px
print('Current DPI is %f' % (curr_dpi))
Which returned:
Width: 1555 px, Height: 875 px
Width: 411 mm, Height: 232 mm
Width: 16.181102 in, Height: 9.133858 in
Width: 96.099757 dpi, Height: 95.797414 dpi
Size is 2560.000000 1440.000000
Current DPI is 158.045016
I am running Windows 8.1 with a 220 DPI capable monitor.
My display scaling sets my current DPI to 158.
I'll use the 158 to make sure my Matplotlib plots are the right size with:
from pylab import rcParams
rcParams['figure.dpi'] = curr_dpi
And for completeness, Mac OS X
import AppKit
[(screen.frame().size.width, screen.frame().size.height)
for screen in AppKit.NSScreen.screens()]
will give you a list of tuples containing all screen sizes (if multiple monitors present)
A cross-platform and easy way to do this is by using Tkinter that comes with nearly all the Python versions, so you don't have to install anything:
import tkinter
root = tkinter.Tk()
root.withdraw()
WIDTH, HEIGHT = root.winfo_screenwidth(), root.winfo_screenheight()
If you are using the Qt toolkit, specifically PySide, you can do the following:
from PySide import QtGui
import sys
app = QtGui.QApplication(sys.argv)
screen_rect = app.desktop().screenGeometry()
width, height = screen_rect.width(), screen_rect.height()
Old question but this is missing.
I'm new to python so please tell me if this is a "bad" solution.
This solution is supported for Windows and MacOS only and it works just for the main screen - but the os is not mentioned in the question.
Measure the size by taking a screenshot. As the screensize should not change this has to be done only once.
There are more elegant solutions if you have a gui toolkit like GTK, wx, ... installed.
see Pillow
pip install Pillow
from PIL import ImageGrab
img = ImageGrab.grab()
print (img.size)
Expanding on #user2366975's answer, to get the current screen size in a multi-screen setup using Tkinter (code in Python 2/3):
try:
# for Python 3
import tkinter as tk
except ImportError:
# for Python 2
import Tkinter as tk
def get_curr_screen_geometry():
"""
Workaround to get the size of the current screen in a multi-screen setup.
Returns:
geometry (str): The standard Tk geometry string.
[width]x[height]+[left]+[top]
"""
root = tk.Tk()
root.update_idletasks()
root.attributes('-fullscreen', True)
root.state('iconic')
geometry = root.winfo_geometry()
root.destroy()
return geometry
(Should work cross-platform, tested on Linux only)
Using Linux, the simplest way is to execute Bash command
xrandr | grep '*'
And parse its output using a regular expression.
Also you can do it through Pygame: Pygame - Get screen size
I am using a get_screen_resolution method in one of my projects like the one below, which is basically an import chain. You can modify this according to Your needs by removing those parts that are not needed and move more likely ports upwards in the chain.
PYTHON_V3 = sys.version_info >= (3,0,0) and sys.version_info < (4,0,0):
#[...]
def get_screen_resolution(self, measurement="px"):
"""
Tries to detect the screen resolution from the system.
#param measurement: The measurement to describe the screen resolution in. Can be either 'px', 'inch' or 'mm'.
#return: (screen_width,screen_height) where screen_width and screen_height are int types according to measurement.
"""
mm_per_inch = 25.4
px_per_inch = 72.0 #most common
try: # Platforms supported by GTK3, Fx Linux/BSD
from gi.repository import Gdk
screen = Gdk.Screen.get_default()
if measurement=="px":
width = screen.get_width()
height = screen.get_height()
elif measurement=="inch":
width = screen.get_width_mm()/mm_per_inch
height = screen.get_height_mm()/mm_per_inch
elif measurement=="mm":
width = screen.get_width_mm()
height = screen.get_height_mm()
else:
raise NotImplementedError("Handling %s is not implemented." % measurement)
return (width,height)
except:
try: #Probably the most OS independent way
if PYTHON_V3:
import tkinter
else:
import Tkinter as tkinter
root = tkinter.Tk()
if measurement=="px":
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
elif measurement=="inch":
width = root.winfo_screenmmwidth()/mm_per_inch
height = root.winfo_screenmmheight()/mm_per_inch
elif measurement=="mm":
width = root.winfo_screenmmwidth()
height = root.winfo_screenmmheight()
else:
raise NotImplementedError("Handling %s is not implemented." % measurement)
return (width,height)
except:
try: #Windows only
from win32api import GetSystemMetrics
width_px = GetSystemMetrics (0)
height_px = GetSystemMetrics (1)
if measurement=="px":
return (width_px,height_px)
elif measurement=="inch":
return (width_px/px_per_inch,height_px/px_per_inch)
elif measurement=="mm":
return (width_px/mm_per_inch,height_px/mm_per_inch)
else:
raise NotImplementedError("Handling %s is not implemented." % measurement)
except:
try: # Windows only
import ctypes
user32 = ctypes.windll.user32
width_px = user32.GetSystemMetrics(0)
height_px = user32.GetSystemMetrics(1)
if measurement=="px":
return (width_px,height_px)
elif measurement=="inch":
return (width_px/px_per_inch,height_px/px_per_inch)
elif measurement=="mm":
return (width_px/mm_per_inch,height_px/mm_per_inch)
else:
raise NotImplementedError("Handling %s is not implemented." % measurement)
except:
try: # Mac OS X only
import AppKit
for screen in AppKit.NSScreen.screens():
width_px = screen.frame().size.width
height_px = screen.frame().size.height
if measurement=="px":
return (width_px,height_px)
elif measurement=="inch":
return (width_px/px_per_inch,height_px/px_per_inch)
elif measurement=="mm":
return (width_px/mm_per_inch,height_px/mm_per_inch)
else:
raise NotImplementedError("Handling %s is not implemented." % measurement)
except:
try: # Linux/Unix
import Xlib.display
resolution = Xlib.display.Display().screen().root.get_geometry()
width_px = resolution.width
height_px = resolution.height
if measurement=="px":
return (width_px,height_px)
elif measurement=="inch":
return (width_px/px_per_inch,height_px/px_per_inch)
elif measurement=="mm":
return (width_px/mm_per_inch,height_px/mm_per_inch)
else:
raise NotImplementedError("Handling %s is not implemented." % measurement)
except:
try: # Linux/Unix
if not self.is_in_path("xrandr"):
raise ImportError("Cannot read the output of xrandr, if any.")
else:
args = ["xrandr", "-q", "-d", ":0"]
proc = subprocess.Popen(args,stdout=subprocess.PIPE)
for line in iter(proc.stdout.readline,''):
if isinstance(line, bytes):
line = line.decode("utf-8")
if "Screen" in line:
width_px = int(line.split()[7])
height_px = int(line.split()[9][:-1])
if measurement=="px":
return (width_px,height_px)
elif measurement=="inch":
return (width_px/px_per_inch,height_px/px_per_inch)
elif measurement=="mm":
return (width_px/mm_per_inch,height_px/mm_per_inch)
else:
raise NotImplementedError("Handling %s is not implemented." % measurement)
except:
# Failover
screensize = 1366, 768
sys.stderr.write("WARNING: Failed to detect screen size. Falling back to %sx%s" % screensize)
if measurement=="px":
return screensize
elif measurement=="inch":
return (screensize[0]/px_per_inch,screensize[1]/px_per_inch)
elif measurement=="mm":
return (screensize[0]/mm_per_inch,screensize[1]/mm_per_inch)
else:
raise NotImplementedError("Handling %s is not implemented." % measurement)
Here is a quick little Python program that will display the information about your multi-monitor setup:
import gtk
window = gtk.Window()
# the screen contains all monitors
screen = window.get_screen()
print "screen size: %d x %d" % (gtk.gdk.screen_width(),gtk.gdk.screen_height())
# collect data about each monitor
monitors = []
nmons = screen.get_n_monitors()
print "there are %d monitors" % nmons
for m in range(nmons):
mg = screen.get_monitor_geometry(m)
print "monitor %d: %d x %d" % (m,mg.width,mg.height)
monitors.append(mg)
# current monitor
curmon = screen.get_monitor_at_window(screen.get_active_window())
x, y, width, height = monitors[curmon]
print "monitor %d: %d x %d (current)" % (curmon,width,height)
Here's an example of its output:
screen size: 5120 x 1200
there are 3 monitors
monitor 0: 1600 x 1200
monitor 1: 1920 x 1200
monitor 2: 1600 x 1200
monitor 1: 1920 x 1200 (current)
X Window version:
#!/usr/bin/python
import Xlib
import Xlib.display
resolution = Xlib.display.Display().screen().root.get_geometry()
print str(resolution.width) + "x" + str(resolution.height)
In case you have PyQt4 installed, try the following code:
from PyQt4 import QtGui
import sys
MyApp = QtGui.QApplication(sys.argv)
V = MyApp.desktop().screenGeometry()
h = V.height()
w = V.width()
print("The screen resolution (width X height) is the following:")
print(str(w) + "X" + str(h))
For PyQt5, the following will work:
from PyQt5 import QtWidgets
import sys
MyApp = QtWidgets.QApplication(sys.argv)
V = MyApp.desktop().screenGeometry()
h = V.height()
w = V.width()
print("The screen resolution (width X height) is the following:")
print(str(w) + "X" + str(h))
On Linux:
import subprocess
import re
def getScreenDimensions():
xrandrOutput = str(subprocess.Popen(['xrandr'], stdout=subprocess.PIPE).communicate()[0])
matchObj = re.findall(r'current\s(\d+) x (\d+)', xrandrOutput)
if matchObj:
return (int(matchObj[0][0]), int(matchObj[0][1]))
screenWidth, screenHeight = getScreenDimensions()
print(f'{screenWidth} x {screenHeight}')
Try pyautogui:
import pyautogui
resolution = pyautogui.size()
print(resolution)
A lot of these answers use tkinter to find the screen height/width (resolution), but sometimes it is necessary to know the dpi of your screen cross-platform compatible.
This answer is from this link and left as a comment on another post, but it took hours of searching to find. I have not had any issues with it yet, but please let me know if it does not work on your system!
import tkinter
root = tkinter.Tk()
dpi = root.winfo_fpixels('1i')
The documentation for this says:
winfo_fpixels(number)
# Return the number of pixels for the given distance NUMBER (e.g. "3c") as float
A distance number is a digit followed by a unit, so 3c means 3 centimeters, and the function gives the number of pixels on 3 centimeters of the screen (as found here).
So to get dpi, we ask the function for the number of pixels in 1 inch of screen ("1i").
Using pygame:
import pygame
pygame.init()
infos = pygame.display.Info()
screen_size = (infos.current_w, infos.current_h)
[1]
However, if you're trying to set your window to the size of the screen, you might just want to do:
pygame.display.set_mode((0,0),pygame.FULLSCREEN)
to set your display to fullscreen mode. [2]
If you are working on Windows OS, you can use OS module to get it:
import os
cmd = 'wmic desktopmonitor get screenheight, screenwidth'
size_tuple = tuple(map(int,os.popen(cmd).read().split()[-2::]))
It will return a tuple (Y,X) where Y is the vertical size and X is the horizontal size. This code works on Python 2 and Python 3
UPDATE
For Windows 8/8.1/10, the above answer doesn't work, use the next one instead:
import os
cmd = "wmic path Win32_VideoController get CurrentVerticalResolution,CurrentHorizontalResolution"
size_tuple = tuple(map(int,os.popen(cmd).read().split()[-2::]))
Using Linux
Instead of a regular expression, take the first line and take out the current resolution values.
Current resolution of display :0
>>> screen = os.popen("xrandr -q -d :0").readlines()[0]
>>> print screen
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 1920 x 1920
>>> width = screen.split()[7]
>>> print width
1920
>>> height = screen.split()[9][:-1]
>>> print height
1080
>>> print "Current resolution is %s x %s" % (width,height)
Current resolution is 1920 x 1080
This was done on xrandr 1.3.5, I don't know if the output is different on other versions, but this should make it easy to figure out.
Late to the game. I think I found the cross-platform using the dependence-free library mss that supports multiple monitors (https://pypi.org/project/mss/):
import mss
sct=mss.mss()
sct.monitors
Then you get something like this:
[{'left': -1440, 'top': 0, 'width': 4000, 'height': 1080},
{'left': 0, 'top': 0, 'width': 2560, 'height': 1080},
{'left': -1440, 'top': 180, 'width': 1440, 'height': 900}]
The element 0 is the virtual screen combining all monitors. The element 1 is the primary monitor, and element 2 the second monitor.
To get bits per pixel:
import ctypes
user32 = ctypes.windll.user32
gdi32 = ctypes.windll.gdi32
screensize = (user32.GetSystemMetrics(0), user32.GetSystemMetrics(1))
print "screensize =%s"%(str(screensize))
dc = user32.GetDC(None);
screensize = (gdi32.GetDeviceCaps(dc,8), gdi32.GetDeviceCaps(dc,10), gdi32.GetDeviceCaps(dc,12))
print "screensize =%s"%(str(screensize))
screensize = (gdi32.GetDeviceCaps(dc,118), gdi32.GetDeviceCaps(dc,117), gdi32.GetDeviceCaps(dc,12))
print "screensize =%s"%(str(screensize))
parameters in gdi32:
#/// Vertical height of entire desktop in pixels
#DESKTOPVERTRES = 117,
#/// Horizontal width of entire desktop in pixels
#DESKTOPHORZRES = 118,
#/// Horizontal width in pixels
#HORZRES = 8,
#/// Vertical height in pixels
#VERTRES = 10,
#/// Number of bits per pixel
#BITSPIXEL = 12,
Another version using xrandr:
import re
from subprocess import run, PIPE
output = run(['xrandr'], stdout=PIPE).stdout.decode()
result = re.search(r'current (\d+) x (\d+)', output)
width, height = map(int, result.groups()) if result else (800, 600)
You could use PyMouse. To get the screen size just use the screen_size() attribute:
from pymouse import PyMouse
m = PyMouse()
a = m.screen_size()
a will return a tuple, (X, Y), where X is the horizontal position and Y is the vertical position.
Link to function in documentation.
For later versions of PyGtk:
import gi
gi.require_version("Gdk", "3.0")
from gi.repository import Gdk
display = Gdk.Display.get_default()
n_monitors = display.get_n_monitors()
print("there are %d monitors" % n_monitors)
for m in range(n_monitors):
monitor = display.get_monitor(m)
geometry = monitor.get_geometry()
print("monitor %d: %d x %d" % (m, geometry.width, geometry.height))
For Linux, you can use this:
import gi
gi.require_version("Gdk", "3.0")
from gi.repository import Gdk
s = Gdk.Screen.get_default()
screen_width = s.get_width()
screen_height = s.get_height()
print(screen_width)
print(screen_height)
On Linux we can use subprocess module
import subprocess
cmd = ['xrandr']
cmd2 = ['grep', '*']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
p2 = subprocess.Popen(cmd2, stdin=p.stdout, stdout=subprocess.PIPE)
p.stdout.close()
resolution_string, junk = p2.communicate()
resolution = resolution_string.split()[0]
resolution = resolution.decode("utf-8")
width = int(resolution.split("x")[0].strip())
heigth = int(resolution.split("x")[1].strip())
It's a little troublesome for retina screen, i use tkinter to get the fake size, use pilllow grab to get real size :
import tkinter
root = tkinter.Tk()
resolution_width = root.winfo_screenwidth()
resolution_height = root.winfo_screenheight()
image = ImageGrab.grab()
real_width, real_height = image.width, image.height
ratio_width = real_width / resolution_width
ratio_height = real_height/ resolution_height

Categories

Resources