I have seen this code sequence described in various incarnations on these forums and is purported to work. However, most of the developers using it are on windows. I saw a vague reference somewhere that perhaps this does not work on OS X with retina displays. In fact, I am running on the latest Catalina release on a 2016 MBP. Running this code on Python 3.8.2 and wxpython 4.1.0 produces an image file (.png, .bmp, or .jpg) that is totally black. Am I missing something here:
Note I am using 4.0.7 on OpenSuse 15.1 python3.6
wx._core.wxAssertionError: C++ assertion âid == wxID_ANY || (id >= 0 && id < 32767) || (id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST)â failed at /home/abuild/rpmbuild/BUILD/wxPython-4.0.7.post1/ext/wxWidgets/src/common/wincmn.cpp(372) in CreateBase(): invalid id value
Using 4.1.x on Ubuntu 20 python 3.8.x I get the same message:
wx._core.wxAssertionError: C++ assertion âid == wxID_ANY || (id >= 0 && id < 32767) || (id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST)â failed at /home/wxpy/wxPython-4.1.0/ext/wxWidgets/src/common/wincmn.cpp(375) in CreateBase(): invalid id value
A little debugging I realized that you were setting the following:
FRAME_ID: int = 0xDeadBeef
I imported wx
and
FRAME_ID: int = wx.ID_ANY
That then creates a button at the upper left, and pic in the center of the frame and I can move it with the mouse. BTW this worked with both wxPython 4.0.7 and 4.1
No, I do not see a saved file. But I also believe the img.SaveFile(filename, imageType) is using the core.pyi(r/o) Image->SaveFile() which does nothing. I normally do not work with images and could be talking out of my backside. So take this with a grain of salt.
# adjust widths for Linux (figured out by John Torres
# http://article.gmane.org/gmane.comp.python.wxpython/67327)
if sys.platform == 'linux2':
client_x, client_y = self.ClientToScreen((0, 0))
border_width = client_x - rect.x
title_bar_height = client_y - rect.y
rect.width += (border_width * 2)
rect.height += title_bar_height + border_width
#Create a DC for the whole screen area
dcScreen = wx.ScreenDC()
#Create a Bitmap that will hold the screenshot image later on
#Note that the Bitmap must have a size big enough to hold the screenshot
#-1 means using the current default colour depth
bmp = wx.EmptyBitmap(rect.width, rect.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
#and thus the Bitmap
memDC.Blit( 0, #Copy to this X coordinate
0, #Copy to this Y coordinate
rect.width, #Copy this width
rect.height, #Copy this height
dcScreen, #From where do we copy?
rect.x, #What's the X offset in the original DC?
rect.y #What's the Y offset in the original DC?
)
#Select the Bitmap out of the memory DC by selecting a new
#uninitialized Bitmap
memDC.SelectObject(wx.NullBitmap)
img = bmp.ConvertToImage()
fileName = "myImage.png"
img.SaveFile(fileName, wx.BITMAP_TYPE_PNG)
print ('...saving as png!')
On my OpenSuse 15.1 python 3.6.x wxPython 4.0.7 I am able to over write the file many times without error. meaning I get a new time stamp when I save to myImage.png. Karsten_hilbert - maybe you are talking about something other than the code I posted???
Maybe the title of this post was misleading. What I was trying to âscreenshotâ was the screen that was displayed int the client window. Which should be as displayed in the following image: https://github.com/hasii2011/PyUt/wiki/pics/CaptureImage.png
Unfortunately the screen-related DCs (Paint, Client, Window, Screen) on OSX are essentially write-only, and have been for a number of years. (Ever since wxMac switched from QuickDraw to CoreGraphics, if I remember correctly.) That means that they canât retrieve pixels from the screen buffer, they can only draw. The reason behind this is that the newer display tech in the OS controls all drawing from all apps so it can optimize it, so the application itself is actually separated from the display buffer by a few more layers.
A possible workaround might be to use applescript to control the OS or some native app to take a screenshot, and then load and manipulate that image as needed. ISTR seeing something like that being done, but I couldnât find any details about it.
Ok. Thanks for this information. I thought I had read something like this somewhere in a google search but could not find it. Iâll try some other mechanism
Hmm. That is sad. So there is no way to capture the contents of a client window in a bitmap other than to launch some external app, figure out the part of the screen to capture and then do that. This seems like a problem I should work on with the core wxPython team. How would I do that? Checkout wxpython, hack a bunch of code and try to get the team to merge the code back to the mainline? Someone, please advise?