Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple screenshots using ScreenDC issue #259

Closed
proggeo opened this issue Mar 24, 2017 · 12 comments
Closed

Multiple screenshots using ScreenDC issue #259

proggeo opened this issue Mar 24, 2017 · 12 comments

Comments

@proggeo
Copy link

proggeo commented Mar 24, 2017

If you take a screenshot with wx.ScreenDC() for few times, then every time you will get the same image: the screenshot at the moment when wx.ScreenDC() was called for the first time. The only solution found is to run it every time in separate Process with its own wx.App() inside.

However, if you do this on wxPython Classic, it works just fine.
Sample code down here:

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()
@nepix32
Copy link

nepix32 commented Mar 25, 2017

Has been asked (with possible working answer) on Stackoverflow.

@ncqgm
Copy link

ncqgm commented Aug 12, 2019

I do not think this issue is solved:
http://wxpython-users.1045709.n5.nabble.com/wx-ScreenDC-screenshotting-problems-td5730158.html
Please re-check.
Thanks,
Karsten

@swt2c
Copy link
Collaborator

swt2c commented Aug 12, 2019

I see this also with Classic (but built against GTK 3), so I think this is probably rather something to do with the GTK 3 implementation of wxScreenDC and nothing wxPython specific. Probably needs a C++ reproducer and ticket opened on trac.wxwidgets.org.

@RobinD42
Copy link
Member

Yep, there are also similar problems with OSX.

My understanding is that due to the additional layers between the applications and the display for automatic buffering and compositing, that we don't have the same level of access to the display's image buffer that we had before with the older systems, and so we simply can not fetch what is displayed on the screen via the wx.ScreenDC API in order to Blit it into a bitmap. I think I saw somebody say that you can think of wx.ScreenDC being a write-only interface now.

That said, on OSX you can use wx.ScreenDC.GetAsBitmap to get an image of the screen. It's not implemented for GTK3 unfortunately.

@ncqgm
Copy link

ncqgm commented Aug 13, 2019 via email

@infinity77
Copy link
Contributor

infinity77 commented Aug 13, 2019 via email

@ncqgm
Copy link

ncqgm commented Aug 13, 2019 via email

@ncqgm
Copy link

ncqgm commented Aug 13, 2019 via email

@ncqgm
Copy link

ncqgm commented Aug 14, 2019 via email

@The-o
Copy link

The-o commented Mar 18, 2021

Faced the same problem on Ubuntu 19.10, wxPython 4.0.6 gtk3 (phoenix) wxWidgets 3.0.4, python 3.7.5.
And it seems I found workaround:

Just insert screen.Blit(0, 0, width, height, screen, 0, 0) after mem.Blit(0, 0, width, height, screen, 0, 0). So the working (for my setup) version of the code is:

import wx
from datetime import datetime
from time import sleep

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)

    screen.Blit(0, 0, width, height, screen, 0, 0) # <-- this line makes multiple screenshots work

    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()

upd:

It is better to use wx.OR logical function in screen-on-screen blitting (screen.Blit(0, 0, width, height, screen, 0, 0, wx.OR)), because oherwise in Windows it paints the screen white.

@ncqgm
Copy link

ncqgm commented Mar 19, 2021 via email

@The-o
Copy link

The-o commented Mar 20, 2021

It perhaps "updates" a globally cached (?) Screen DC from layers further down, closer to the hardware ?

I don't really know how and why it works. I believe it is something to do with wxWidgets and not with wxPython itself.
I just saw that thare was a different if-branch in the latest wxWidgets GTK DC implementation when the source and the destination DCs were the same (https://github.com/wxWidgets/wxWidgets/blob/v3.1.4/src/gtk/dc.cpp#L152). Then the idea of trying to repaint screen with its own content came to me. And it surprisingly worked.

But the confusing fact is that there is no such an if-branch in wxWidgets v3.0.4 I have (https://github.com/wxWidgets/wxWidgets/blob/v3.0.4/src/gtk/dc.cpp#L138). And I'm not good at cairo, so the mystery of why the workaround works still remains for me.

ncqgm added a commit to ncqgm/gnumed that referenced this issue Mar 20, 2021
	The-o found a workaround for the problem that taking
	consecutive screenshots of a ScreenDC always returned
	the same (initial) image.

	wxWidgets/Phoenix#259 (comment)

(cherry picked from commit 513cd90)
ncqgm added a commit to ncqgm/gnumed that referenced this issue May 10, 2021
	The-o found a workaround for the problem that taking
	consecutive screenshots of a ScreenDC always returned
	the same (initial) image.

	wxWidgets/Phoenix#259 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants