cross-platform screenshot tool?

I would like a way to take a screenshot of the desktop from within my
wxPython application, and I need this to work on all major platforms.
I've seen a solution from a thread back in 2006 but wonder if now
there is a module or widget or something to do this. What I _really_
want is the ability for the user to draw a rectangle anywhere on the
display and grab that, or click on any window, though I would settle
for the whole desktop.

Does such a thing already exist or am I going to have to roll my own
using a ScreenDC?

Thanks

WxPython provides a way to make an application capture of only itself. As far as I know, there is no cross-platform screen shot utility. However, there seems to be multiple free screen capture utilities for every platform.
Getting a full screen capture is entirely in the realm of the particular OS platform. I’m guessing that the easiest route for you to take is to use free third-party command-line based capture utilities for each platform and include the appropriate one in your installer program for each platform. If an app needs to be compiled from source for, say, a particular Linux platform, then this needs to be done by your app installer program.
Getting your wxPython app to run the capture utility and to read and manipulate the resulting image from a file or even from a clipboard (if the particular utility supports this) should be straight forward.
Drawing directly on the screen (MSW’s Desktop, for example) is also extremely platform dependent, but should be possible in every platform. For MSW, for example, see :

[Drawing on the Windows desktop using Python and wxPython](http://www.michaelfogleman.com/2009/12/drawing-on-the-windows-desktop-using-python-and-wxpython/) 

I have no idea how many platforms in which wxPython supports full screen drawing.

···

On Mon, Mar 21, 2011 at 12:29 PM, Bryan Oakley bryan.oakley@gmail.com wrote:

I would like a way to take a screenshot of the desktop from within my

wxPython application, and I need this to work on all major platforms.

I’ve seen a solution from a thread back in 2006 but wonder if now

there is a module or widget or something to do this. What I really

want is the ability for the user to draw a rectangle anywhere on the

display and grab that, or click on any window, though I would settle

for the whole desktop.

Does such a thing already exist or am I going to have to roll my own

using a ScreenDC?

Thanks

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

On Mar 21, 12:29 pm, Bryan Oakley bryan.oak...@gmail.com wrote:

I would like a way to take a screenshot of the desktop from within my
wxPython application, and I need this to work on all major platforms.
I’ve seen a solution from a thread back in 2006 but wonder if now
there is a module or widget or something to do this. What I really
want is the ability for the user to draw a rectangle anywhere on the
display and grab that, or click on any window, though I would settle
for the whole desktop.

Does such a thing already exist or am I going to have to roll my own
using a ScreenDC?

Thanks


Messy ? For sure, but this seems workable and reliable for as many platforms (and platform versions) as you care to support.

Ray Pasco

AFAIK, you'll need to roll your own with a ScreenDC. I don't recall seeing any existing code/classes for doing it, especially since you would like to be able to select a subset of the screen image. Unfortunately it's probably not going to work at all on OSX however, as since the switch to the CoreGraphic APIs we no longer have read access to the screen buffer. But there is probably a way to do a workaround there, such as using some other tool or some PyObjC code to grab the screen shot and then view it in a wx.Window where you allow the user to select a subset.

···

On 3/21/11 9:29 AM, Bryan Oakley wrote:

I would like a way to take a screenshot of the desktop from within my
wxPython application, and I need this to work on all major platforms.
I've seen a solution from a thread back in 2006 but wonder if now
there is a module or widget or something to do this. What I _really_
want is the ability for the user to draw a rectangle anywhere on the
display and grab that, or click on any window, though I would settle
for the whole desktop.

Does such a thing already exist or am I going to have to roll my own
using a ScreenDC?

--
Robin Dunn
Software Craftsman

Hi Robin,

I would like a way to take a screenshot of the desktop from within my
wxPython application, and I need this to work on all major platforms.
I've seen a solution from a thread back in 2006 but wonder if now
there is a module or widget or something to do this. What I _really_
want is the ability for the user to draw a rectangle anywhere on the
display and grab that, or click on any window, though I would settle
for the whole desktop.

Does such a thing already exist or am I going to have to roll my own
using a ScreenDC?

AFAIK, you'll need to roll your own with a ScreenDC. I don't recall seeing any existing code/classes for doing it, especially since you would like to be able to select a subset of the screen image. Unfortunately it's probably not going to work at all on OSX however, as since the switch to the CoreGraphic APIs we no longer have read access to the screen buffer.

We were able to implement wx.ScreenDC.GetAsBitmap using OpenGL instead for the CG backend. It did work last I tried it, but I haven't tested it in a long time.

Also, for selecting a subset of the screen image, what about using a transparent, full-screen frame and using a wx.DCOverlay to draw the selection rectangle?

But there is probably a way to do a workaround there, such as using some other tool or some PyObjC code to grab the screen shot and then view it in a wx.Window where you allow the user to select a subset.

Of course, this would work too. :slight_smile:

Regards,

Kevin

···

On Mar 21, 2011, at 4:06 PM, Robin Dunn wrote:

On 3/21/11 9:29 AM, Bryan Oakley wrote:

--
Robin Dunn
Software Craftsman
http://wxPython.org

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

Indeed. I seem to always forget about that, I guess I need to update my memory search algorithm...

···

On 3/22/11 7:45 AM, Kevin Ollivier wrote:

Hi Robin,

On Mar 21, 2011, at 4:06 PM, Robin Dunn wrote:

On 3/21/11 9:29 AM, Bryan Oakley wrote:

I would like a way to take a screenshot of the desktop from within my
wxPython application, and I need this to work on all major platforms.
I've seen a solution from a thread back in 2006 but wonder if now
there is a module or widget or something to do this. What I _really_
want is the ability for the user to draw a rectangle anywhere on the
display and grab that, or click on any window, though I would settle
for the whole desktop.

Does such a thing already exist or am I going to have to roll my own
using a ScreenDC?

AFAIK, you'll need to roll your own with a ScreenDC. I don't recall seeing any existing code/classes for doing it, especially since you would like to be able to select a subset of the screen image. Unfortunately it's probably not going to work at all on OSX however, as since the switch to the CoreGraphic APIs we no longer have read access to the screen buffer.

We were able to implement wx.ScreenDC.GetAsBitmap using OpenGL instead for the CG backend. It did work last I tried it, but I haven't tested it in a long time.

--
Robin Dunn
Software Craftsman

I use the code below, only tested it on Windows, but I don't think it contains anything platform
specifics.
(The code could be 1*1 pixel wrong, didn't have time to test that )

cheers,
Stef

# ***********************************************************************
# ***********************************************************************
class _Screen_Capture ( wx.Dialog ) :

  def __init__(self, Filename, parent = None ) :
    self.Filename = Filename
    self.c1 = None
    self.c2 = None
    wx.Dialog.__init__( self, parent, -1, '', size=wx.DisplaySize(),
                       style = wx.SYSTEM_MENU | wx.FRAME_NO_TASKBAR | wx.NO_BORDER )

    self.panel = wx.Panel (self, size=self.GetSize () )
    self.SetTransparent ( 50 )

    self.panel.Bind ( wx.EVT_LEFT_DOWN, self.OnMouseDown )
    self.panel.Bind ( wx.EVT_MOTION , self.OnMouseMove )
    self.panel.Bind ( wx.EVT_LEFT_UP , self.OnMouseUp )
    self.panel.Bind ( wx.EVT_PAINT , self.OnPaint )

    self.SetCursor ( wx.StockCursor ( wx.CURSOR_CROSS ) )
    self.Show ()

  def OnMouseDown ( self, event ) :
    self.c1 = event.GetPosition()

  def OnMouseMove ( self, event ) :
    if event.Dragging() and event.LeftIsDown():
      self.c2 = event.GetPosition()
      self.Refresh()

  def OnMouseUp ( self, event ) :
    ## Don't know for sure that +(1,1) is correct ??
    self.c1 = self.ClientToScreen ( self.c1 ) + ( 1, 1 )
    self.c2 = self.ClientToScreen ( self.c2 ) + ( 1, 1 )
    x0 = self.c1.x
    x1 = self.c2.x
    y0 = self.c1.y
    y1 = self.c2.y
    if x0 == x1 or y0 == y1 :
      self.c1 = None
      self.c2 = None
      return

    if x0 > x1 :
      x = x0
      x0 = x1
      x1 = x
    if y0 > y1 :
      y = y0
      y0 = y1
      y1 = y

    from PIL import ImageGrab
    bbox = ( x0, y0, x1, y1 )
    # For bounded bbox, yields, x0, y0 is included, x1, y1 is excluded !!
    ImageGrab.grab ( bbox ).save ( self.Filename )
    self.Close()

  def OnPaint ( self, event ) :
    if ( self.c1 is None ) or ( self.c2 is None ) :
      return

    dc = wx.PaintDC ( self.panel )
    dc.SetPen ( wx.Pen ( 'red', 1 ) )
    dc.SetBrush ( wx.Brush ( wx.Color ( 0, 0, 0 ), wx.TRANSPARENT ))

    dc.DrawRectangle ( self.c1.x, self.c1.y,
                       self.c2.x - self.c1.x, self.c2.y - self.c1.y )
# ***********************************************************************

# ***********************************************************************
# ***********************************************************************
@_Wrap_No_GUI
def Screen_Capture ( Filename, parent = None ) :
  dlg = _Screen_Capture ( Filename, parent )
  dlg.ShowModal()
  dlg.Destroy()
# ***********************************************************************

···

On 21-03-2011 17:29, Bryan Oakley wrote:

I would like a way to take a screenshot of the desktop from within my
wxPython application, and I need this to work on all major platforms.
I've seen a solution from a thread back in 2006 but wonder if now
there is a module or widget or something to do this. What I _really_
want is the ability for the user to draw a rectangle anywhere on the
display and grab that, or click on any window, though I would settle
for the whole desktop.

Does such a thing already exist or am I going to have to roll my own
using a ScreenDC?

Thanks

Looks good, but what's the code for the no gui wrapper?

Josh

···

On Wed, Mar 23, 2011 at 11:37 AM, Stef Mientki <stef.mientki@gmail.com> wrote:

On 21-03-2011 17:29, Bryan Oakley wrote:

I would like a way to take a screenshot of the desktop from within my
wxPython application, and I need this to work on all major platforms.
I've seen a solution from a thread back in 2006 but wonder if now
there is a module or widget or something to do this. What I _really_
want is the ability for the user to draw a rectangle anywhere on the
display and grab that, or click on any window, though I would settle
for the whole desktop.

Does such a thing already exist or am I going to have to roll my own
using a ScreenDC?

Thanks

I use the code below, only tested it on Windows, but I don't think it contains anything platform
specifics.
(The code could be 1*1 pixel wrong, didn't have time to test that )

cheers,
Stef

# ***********************************************************************
# ***********************************************************************
class _Screen_Capture ( wx.Dialog ) :

def __init__(self, Filename, parent = None ) :
self.Filename = Filename
self.c1 = None
self.c2 = None
wx.Dialog.__init__( self, parent, -1, '', size=wx.DisplaySize(),
style = wx.SYSTEM_MENU | wx.FRAME_NO_TASKBAR | wx.NO_BORDER )

self.panel = wx.Panel (self, size=self.GetSize () )
self.SetTransparent ( 50 )

self.panel.Bind ( wx.EVT_LEFT_DOWN, self.OnMouseDown )
self.panel.Bind ( wx.EVT_MOTION , self.OnMouseMove )
self.panel.Bind ( wx.EVT_LEFT_UP , self.OnMouseUp )
self.panel.Bind ( wx.EVT_PAINT , self.OnPaint )

self.SetCursor ( wx.StockCursor ( wx.CURSOR_CROSS ) )
self.Show ()

def OnMouseDown ( self, event ) :
self.c1 = event.GetPosition()

def OnMouseMove ( self, event ) :
if event.Dragging() and event.LeftIsDown():
self.c2 = event.GetPosition()
self.Refresh()

def OnMouseUp ( self, event ) :
## Don't know for sure that +(1,1) is correct ??
self.c1 = self.ClientToScreen ( self.c1 ) + ( 1, 1 )
self.c2 = self.ClientToScreen ( self.c2 ) + ( 1, 1 )
x0 = self.c1.x
x1 = self.c2.x
y0 = self.c1.y
y1 = self.c2.y
if x0 == x1 or y0 == y1 :
self.c1 = None
self.c2 = None
return

if x0 > x1 :
x = x0
x0 = x1
x1 = x
if y0 > y1 :
y = y0
y0 = y1
y1 = y

from PIL import ImageGrab
bbox = ( x0, y0, x1, y1 )
# For bounded bbox, yields, x0, y0 is included, x1, y1 is excluded !!
ImageGrab.grab ( bbox ).save ( self.Filename )
self.Close()

def OnPaint ( self, event ) :
if ( self.c1 is None ) or ( self.c2 is None ) :
return

dc = wx.PaintDC ( self.panel )
dc.SetPen ( wx.Pen ( 'red', 1 ) )
dc.SetBrush ( wx.Brush ( wx.Color ( 0, 0, 0 ), wx.TRANSPARENT ))

dc.DrawRectangle ( self.c1.x, self.c1.y,
self.c2.x - self.c1.x, self.c2.y - self.c1.y )
# ***********************************************************************

# ***********************************************************************
# ***********************************************************************
@_Wrap_No_GUI
def Screen_Capture ( Filename, parent = None ) :
dlg = _Screen_Capture ( Filename, parent )
dlg.ShowModal()
dlg.Destroy()
# ***********************************************************************

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

--
Josh English
Joshua.R.English@gmail.com

well you only need the gui wrapper if you use it outside a wxPython application,
but for completeness it's below.

cheers,
Stef

# ***********************************************************************
# ***********************************************************************
def _Wrap_No_GUI ( target ):
  """
  Decorator that creates an wx.App is it's not yet there,
  so wx functions can be used in terminal mode applications.
  The actions that are performed:
    - Create the wx.App, it it doesn't exist
    - run the normal wx-dialog function (or any other wx-form)
    - Kill the application if it was created here
  """
  def wrapper ( *args, **kwargs ) :
    # Create the Application if it doesn't exists
    _dummy_app = None
    if not ( wx.GetApp () ):
      _dummy_app = wx.PySimpleApp ()
      global _Wrap_No_GUI_Active
      _Wrap_No_GUI_Active = True

    # perform the called target function
    result = target ( *args, **kwargs )

    # Destroy the wx.App, if it was created here
    if _dummy_app :
      _dummy_app.Destroy ()
      _dummy_app = None

    # return the result to the calling application
    return result

  # ??? don't know what this is for ???
  return wrapper
# ***********************************************************************

···

On 23-03-2011 21:38, Josh English wrote:

Looks good, but what's the code for the no gui wrapper?

I found a simple Desktop grabber that works under MSW and supposedly Linux, too. I didn’t test under Linux, but it looks like a hack.

Take a screenshot via a python script. [Linux] (Using GTK)

ImageMagick

ScreenShot_Demo.py (1.15 KB)

···

Stef : Why does the screen turn gray and be captured that way ?


It should be straight forward to simply get the coordinates of the mouse rectangle, capture the entire screen and then clip the screen shot to those coords.

  I found a simple Desktop grabber that works under MSW

and supposedly Linux, too. I didn’t test under Linux, but it
looks like a hack.

  [        Take

a screenshot via a python script. [Linux] (Using GTK](Take a screenshot via a Python script on Linux - Stack Overflow))

  [ImageMagick](http://www.imagemagick.org/script/index.php)



  -----



  Stef :  Why does the screen turn gray and be captured that way ?
Sorry I don't know anymore, I'm not sure I did this on purpose or

not,

it's a while ago I made this.

cheers,

Stef
···

wxPython-users+unsubscribe@googlegroups.com
http://groups.google.com/group/wxPython-users?hl=en

This appears to be a cross-platform WX way to capture the entire Desktop screen(s). It can easily be tailored to capture just a fraction of the screen.

CaptureDesktop.py (1.32 KB)

Thanks very much! I figured the solution might look something like
that but I have absolutely zero experience with the *DC functions and
didn't know quite where to begin. This looks very promising.

···

On Fri, Mar 25, 2011 at 1:15 AM, Ray Pasco <pascor22234@gmail.com> wrote:

This appears to be a cross-platform WX way to capture the entire Desktop
screen(s). It can easily be tailored to capture just a fraction of the
screen.

… but I have absolutely zero experience with the *DC functions and

didn’t know quite where to begin. This looks very promising.

DC’s are just wx tools, like sizers. They write onto wx.Bitmaps and can also copy (paste) one bitmap onto another bitmap. There are about a half dozen flavors (flavours) of basic DC’s. Choosing the best one for a particular application is beyond the scope of this thread.

A wx.MemoryDC exists only in your system’s RAM and lets you draw on and copy other bitmaps into it. In this screenshot app another DC, the wx.ScreenDC, automatically contains a snapshot of the screen, but has to be copied (using a Blit, Block Level data Transfer) to the MemoryDC so that you can access the MemoryDC’s bitmap. When you finish using the MemoryDC, the bitmap being operated on by this DC must be released from the DC by calling :

memDC.SelectObject( wx.NullBitmap )  # Permanently disassociate this DC from its bitmap

After the bitmap is released from the MemoryDC, you can do anything you want with it like any other bitmap such as displaying it as a control or saving it to a graphics file:

# Display it:
self.stBmap = wx.StaticBitmap( self.frmPanel, wx.ID_ANY, bmap )

and
# Save the image to a disk file:
bmap.SaveFile( ‘CAPTURE_DESKTOP.PNG’, wx.BITMAP_TYPE_PNG )

···

On Fri, Mar 25, 2011 at 1:15 AM, Ray Pasco pascor22234@gmail.com wrote:


Ray Pasco

Hi Ray,

… but I have absolutely zero experience with the *DC functions and

didn’t know quite where to begin. This looks very promising.

DC’s are just wx tools, like sizers. They write onto wx.Bitmaps and can also copy (paste) one bitmap onto another bitmap. There are about a half dozen flavors (flavours) of basic DC’s. Choosing the best one for a particular application is beyond the scope of this thread.

That’s incorrect, only wx.MemoryDC writes onto a wx.Bitmap. Some DCs on some platforms do write to an underlying bitmap, but that is an implementation detail only. And a DC, which stands for ‘device context’, comes from Windows terminology and wraps a native object like most other wx classes do. It’s nothing specific to wx, like sizers are. I wonder what gave you that idea?

A wx.MemoryDC exists only in your system’s RAM and lets you draw on and copy other bitmaps into it. In this screenshot app another DC, the wx.ScreenDC, automatically contains a snapshot of the screen,

No, wx.ScreenDC gives you access to the device context for the screen. It is a representation of whatever is on the screen at the time, and allows you to actually draw on the screen using DC APIs. It is not a screenshot and will not create one unless you call wx.ScreenDC.GetAsBitmap(). Which, BTW, would have reduced your ScreenCap() method to one to one line - ‘return wx.ScreenDC().GetAsBitmap()’. :slight_smile:

Note that the approach you took is probably going to have problems on Mac, if it even works at all. GetAsBitmap is the only officially supported way to get a bitmap from a wx.ScreenDC cross-platform.

Regards,

Kevin

···

On Mar 25, 2011, at 10:29 AM, Ray Pasco wrote:

On Fri, Mar 25, 2011 at 1:15 AM, Ray Pasco pascor22234@gmail.com wrote:

but has to be copied (using a Blit, Block Level data Transfer) to the MemoryDC so that you can access the MemoryDC’s bitmap. When you finish using the MemoryDC, the bitmap being operated on by this DC must be released from the DC by calling :

memDC.SelectObject( wx.NullBitmap )  # Permanently disassociate this DC from its bitmap

After the bitmap is released from the MemoryDC, you can do anything you want with it like any other bitmap such as displaying it as a control or saving it to a graphics file:

# Display it:
self.stBmap = wx.StaticBitmap( self.frmPanel, wx.ID_ANY, bmap )

and
# Save the image to a disk file:
bmap.SaveFile( ‘CAPTURE_DESKTOP.PNG’, wx.BITMAP_TYPE_PNG )


Ray Pasco

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

... Which, BTW, would
have reduced your ScreenCap() method to one to one line - 'return
wx.ScreenDC().GetAsBitmap()'. :slight_smile:

That's promising, but I would have expected the following to work and it didn't:

bm=wx.ScreenDC().GetAsBitmap()
bm.SaveFile("/tmp/wx_screencap.png", wx.BITMAP_TYPE_PNG)

False

Should that have worked? /tmp exists (this is a unix box) but all I
get is a rather unhelpful False result.

···

On Fri, Mar 25, 2011 at 12:56 PM, Kevin Ollivier <kevin-lists@theolliviers.com> wrote:

Check bm.IsOk(). If it returns False then you can use the other technique to blit from the screen DC to a memory DC.

···

On 3/25/11 11:19 AM, Bryan Oakley wrote:

On Fri, Mar 25, 2011 at 12:56 PM, Kevin Ollivier > <kevin-lists@theolliviers.com> wrote:

... Which, BTW, would
have reduced your ScreenCap() method to one to one line - 'return
wx.ScreenDC().GetAsBitmap()'. :slight_smile:

That's promising, but I would have expected the following to work and it didn't:

bm=wx.ScreenDC().GetAsBitmap()
bm.SaveFile("/tmp/wx_screencap.png", wx.BITMAP_TYPE_PNG)

False

Should that have worked? /tmp exists (this is a unix box) but all I
get is a rather unhelpful False result.

--
Robin Dunn
Software Craftsman

Hi Bryan,

... Which, BTW, would
have reduced your ScreenCap() method to one to one line - 'return
wx.ScreenDC().GetAsBitmap()'. :slight_smile:

That's promising, but I would have expected the following to work and it didn't:

bm=wx.ScreenDC().GetAsBitmap()
bm.SaveFile("/tmp/wx_screencap.png", wx.BITMAP_TYPE_PNG)

False

Should that have worked? /tmp exists (this is a unix box) but all I
get is a rather unhelpful False result.

Wow, sorry, it looks like GetAsBitmap() is only implemented for wx.MemoryDC on GTK. :frowning: I do most of my testing on Win and Mac and this is why I didn't notice it. Looking more closely, Windows implements it everywhere, and Mac implements it for wx.MemoryDC, wx.WindowDC and wx.ScreenDC.

I'd hope someone would implement GetAsBitmap on GTK, maybe using the approach posted, because otherwise you can't use GetAsBitmap cross-platform, but you MUST use it on Mac, so you can't use the other approach cross-platform either. :confused:

Regards,

Kevin

···

On Mar 25, 2011, at 11:19 AM, Bryan Oakley wrote:

On Fri, Mar 25, 2011 at 12:56 PM, Kevin Ollivier > <kevin-lists@theolliviers.com> wrote:

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

I was thinking at some point of generating help files, with a screen
capture, and something like html maps

http://www.javascriptkit.com/howto/imagemap.shtml

Given meta data used to generate screens, it should be possible to
produce most of your help documentation automatically

Nick

···

On 25 March 2011 18:46, Kevin Ollivier <kevin-lists@theolliviers.com> wrote:

Hi Bryan,

On Mar 25, 2011, at 11:19 AM, Bryan Oakley wrote:

On Fri, Mar 25, 2011 at 12:56 PM, Kevin Ollivier >> <kevin-lists@theolliviers.com> wrote:

... Which, BTW, would
have reduced your ScreenCap() method to one to one line - 'return
wx.ScreenDC().GetAsBitmap()'. :slight_smile:

That's promising, but I would have expected the following to work and it didn't:

bm=wx.ScreenDC().GetAsBitmap()
bm.SaveFile("/tmp/wx_screencap.png", wx.BITMAP_TYPE_PNG)

False

Should that have worked? /tmp exists (this is a unix box) but all I
get is a rather unhelpful False result.

Wow, sorry, it looks like GetAsBitmap() is only implemented for wx.MemoryDC on GTK. :frowning: I do most of my testing on Win and Mac and this is why I didn't notice it. Looking more closely, Windows implements it everywhere, and Mac implements it for wx.MemoryDC, wx.WindowDC and wx.ScreenDC.

I'd hope someone would implement GetAsBitmap on GTK, maybe using the approach posted, because otherwise you can't use GetAsBitmap cross-platform, but you MUST use it on Mac, so you can't use the other approach cross-platform either. :confused:

Regards,

Kevin

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

--
Nick

Hi Ray,

… but I have absolutely zero experience with the *DC functions and

didn’t know quite where to begin. This looks very promising.

DC’s are just wx tools, like sizers. They write onto wx.Bitmaps and can also copy (paste) one bitmap onto another bitmap. There are about a half dozen flavors (flavours) of basic DC’s. Choosing the best one for a particular application is beyond the scope of this thread.

That’s incorrect, only wx.MemoryDC writes onto a wx.Bitmap. Some DCs on some platforms do write to an underlying bitmap, but that is an implementation detail only. And a DC, which stands for ‘device context’, comes from Windows terminology and wraps a native object like most other wx classes do. It’s nothing specific to wx, like sizers are. I wonder what gave you that idea?

A DC (which is a poor name) is bitmap manipulation tool, not a visible control, just like a Sizer is a control positioning tool, not a visible control.

Perhaps I should have used a more generic description such as “bitmap”, a 2-dimensional graphical representation.

A wx.MemoryDC exists only in your system’s RAM and lets you draw on and copy other bitmaps into it. In this screenshot app another DC, the wx.ScreenDC, automatically contains a snapshot of the screen,

No, wx.ScreenDC gives you access to the device context for the screen.

I used the term “wx.MemoryDC”, not “wx.ScreenDC” in the above sentence. All DC’s exist only in memory and no where else ! Controls, such as wx.Bitmaps, can also be displayed on the screen.

It is a representation of whatever is on the screen at the time, and allows you to actually draw on the screen using DC APIs. It is not a screenshot and will not create one unless you call wx.ScreenDC.GetAsBitmap(). Which, BTW, would have reduced your ScreenCap() method to one to one line - ‘return wx.ScreenDC().GetAsBitmap()’. :slight_smile:

A definition of Screenshot: “A representation of whatever is on the screen at the time.”

The operating system’s bitmap object of wx.ScreenDC() certainly is a screenshot ! The method GetAsBitmap() is needed, unlike MemoryDC, because the screen capture bitmap is created within its init method and not passed in as a parameter to its init method.

Note that the approach you took is probably going to have problems on Mac, if it even works at all. GetAsBitmap is the only officially supported way to get a bitmap from a wx.ScreenDC cross-platform.

There are many wxPython gaps on Mac’s that are fully functional on both Linux and MSW. This just reflects the Mac’s state of development for wx as compared to Linux and MSW, not that these functions are not possible at all. After all, the Linux and Mac OS’s share a distant common root where MSW is a totally different animal, but MSW shares much common functionality (implemented on purpose) made possible by different means.

Ray

···

On Fri, Mar 25, 2011 at 1:56 PM, Kevin Ollivier kevin-lists@theolliviers.com wrote:

On Mar 25, 2011, at 10:29 AM, Ray Pasco wrote:

On Fri, Mar 25, 2011 at 1:15 AM, Ray Pasco pascor22234@gmail.com wrote:

Regards,

Kevin

but has to be copied (using a Blit, Block Level data Transfer) to the MemoryDC so that you can access the MemoryDC’s bitmap. When you finish using the MemoryDC, the bitmap being operated on by this DC must be released from the DC by calling :

memDC.SelectObject( wx.NullBitmap )  # Permanently disassociate this DC from its bitmap

After the bitmap is released from the MemoryDC, you can do anything you want with it like any other bitmap such as displaying it as a control or saving it to a graphics file:

# Display it:
self.stBmap = wx.StaticBitmap( self.frmPanel, wx.ID_ANY, bmap )

and
# Save the image to a disk file:
bmap.SaveFile( ‘CAPTURE_DESKTOP.PNG’, wx.BITMAP_TYPE_PNG )


Ray Pasco


Ray Pasco

I’ve added a section to the wxPython wiki page WorkingWithImages titled A Flexible Screen Capture App which includes a code download link. It’s well documented, so it contains a nice tutorial for using Blit() which requires many arguments. I ran into a couple of nonfuctional calls which are also documented there. I’ll start another thread specifically about them.
The app is written in “pure” wxPython/Python. For all I know it may only work on MSW. I’m curious to see if it works on any Linux and Mac platforms.

Ray