Screenshot

Is there a way to take a screenshot without purchasing a 3rd party plugin?

Thanks

A Screenshot in Windows or Mac? or with a Xojo App ?

in OSX you can do

dim mshell as new Shell mshell.Execute "screencapture -iW -o -P ~/Desktop/MyScreenshot.png"

1 Like

Thanks for the replies. Both Windows and Mac.

I would like to avoid writing the screenshot to disk if possible. I would like to print it to picture var. I need to take many screenshots in a row, so the disk read/write would be a bottle neck.

Slow and manual answer:

a. Do the Clipboard screen shot,
b. Save the Clipboard contents to disk
c. Restart at a.

How do I do a screen shot using the OS default feature ?

OS X:
a. cmd-shift-ctrl-3 place the screen(s) into the Clipboard
b. cmd-shift-ctrl-4 allows you to choose a part of the screen and place it into the Clipboard
c. cmd-shift-ctrl-4 + space bar + a “later” click place the selected window contents (whole window with title bar, scroll bar, …) in the Clipboard

Windows (check on your machine to be sure, my memory may be wrong):
a. PrintScr put the whole screen(s) into the Clipboard
b. alt+PrintScr put the frontmost window content (with title bar,s croll bar, whatever) into the Clipboard.

There is also a delayed function to make screen shot(s), but it does not respect the HiDPI image value…

How do I save the Clipboard Picture contents to disk ?

Check these pages: Clipboard, Picture and FolderItem.

Dim Clip As New Clipboard
Dim Pict As Picture

If Clip.PictureAvailable Then
// Make here a copy of the Clipboard Picture

// Save here the Picture variable where the Clipboard image was saved to disk
End If

But, if you have many (tons) things to save, this will be a boring task.

What about using DrawInto ?

I never use it, so I cannot make comment.

MBS has a nice pluginset. It works pretty easy.
The screenshot function works on both mac and windows.

dim p as picture
p=screenshotRectMBS(self.left-5,self.top+35,self.width+10,self.height+20)

But of course that is a 3rd party plugin. But very worth purchasing though.

The other option is using declares. This code I found elsewhere on this forum:

 const kCGWindowListOptionAll  = 0
  const kCGNullWindowID = 0
  const  kCGWindowImageDefault   = 0
  
  soft declare sub CGContextDrawImage lib "Carbon" (context as Ptr, rect as NSRect, image as Ptr)
  soft declare function CGWindowListCreateImage lib "Carbon" (r as CGRect, windowList as integer, winID as integer, winImageOptions as integer) as ptr
  dim s as CGRect = CGMakeRect(0,0,Screen(0).width, screen(0).height)
  dim p as ptr = CGWindowListCreateImage(s, kCGWindowListOptionAll, kCGNullWindowID, kCGWindowImageDefault)
  dim thePic as new Picture(s.w,s.h)
  CGContextDrawImage ptr(thepic.Graphics.Handle(Graphics.HandleTypeCGContextRef)),s, p

This code renders a window you specify to memory. Not a screenshot.

Windows using declares:

Function CaptureRect(X As Integer, Y As Integer, Width As Integer, Height As Integer) As Picture
  'Performs a screen capture on the specified screen rectangle.   
  #If TargetWin32 Then
    Declare Function GetDesktopWindow Lib "User32" () As Integer
    Declare Function GetDC Lib "User32" (HWND As Integer) As Integer
    Declare Function BitBlt Lib "GDI32" (DCdest As Integer, xDest As Integer, yDest As Integer, Width As Integer, _
    Height As Integer, DCdource As Integer, xSource As Integer, ySource As Integer, rasterOp As Integer) As Boolean
    Declare Function ReleaseDC Lib "User32" (HWND As Integer, DC As Integer) As Integer
    Const SRCCOPY = &h00CC0020
    Const CAPTUREBLT = &h40000000
    
    If Width = 0 Or Height = 0 Then Return Nil
    Dim screenCap As Picture = New Picture(Width, Height, 24)
    Dim HWND As Integer = GetDesktopWindow()
    Dim SourceDC As Integer = GetDC(HWND)
    Dim DestDC As Integer = screenCap.Graphics.Handle(screenCap.Graphics.HandleTypeHDC)
    Call BitBlt(DestDC, 0, 0, Width, Height, SourceDC, X, Y, SRCCOPY Or CAPTUREBLT)
    Call ReleaseDC(HWND, SourceDC)
    Return screenCap
  #Endif
End Function

Thanks Andrew. That worked great! Exactly what I was looking for.

Edwin- I tried the snippet, I’m getting a “Can’t find a type with this name” for NSRect. Is that part of an old library?

Edwins Code is incomplete.

for a screenshot into clipboard

with selection tool

dim mshell as new Shell mshell.Execute "screencapture -i -c"

selected Window

dim mshell as new Shell mshell.Execute "screencapture -iW -o -c"

screencapture manual

Hello all

I tried the code supplied by Andrew and it works great. I do have an extra question: how can I show the cursor because it is not showing now.

Thanks

Richard

The system does not capture the cursor. This is what I did to have the cursor captured when I click on a window, and the result appears as the backdrop of that window. The same principle can be used to capture the cursor elsewhere.

I have use a 16x16 icon from http://www.fatcow.com/free-icons called appropriately cursor.png.

  • Placed it in a 16x16 canvas2, placed off window (at Top = -100) which make it invisible.
  • Added The CaptureRect method
  • In MouseDown :

Function MouseDown(X As Integer, Y As Integer) As Boolean self.backdrop = CaptureRect(me.left,me.top,me.width,me.height) End Function

In MouseEnter :

Sub MouseEnter() App.MouseCursor = System.Cursors.InvisibleCursor End Sub

In MouseExit :

Sub MouseExit() App.MouseCursor = System.Cursors.InvisibleCursor Canvas2.Top = -100 End Sub

In MouseMove :

Sub MouseMove(X As Integer, Y As Integer) Canvas2.top = Y Canvas2.left = X End Sub

The way it works, in MouseEnter I make the cursor invisible. Then in MouseMove, I have the Canvas2 follow X and Y. When MouseDown occurs, BitBlt inside teh CaptureRect grabs the picture of the canvas instead of the cursor. In MouseExit, I put the Canvas2 back off window, invisible.

You can also use the Canvas visible property.

Thinking about it, the method I posted works only to grab the cursor over the app window. Here is an idea I did not test yet, but it should work.

If one wanted to get a cursor image over the entire screen, the solution would be to create a transparent window with the same technique as /Example Projects/Platform-Specific/Windows/CustomWindowShape with the same cursor image making sure that the white inside the arrow is actually all so lightly grey. Actually RGB(254,254,254) would do the trick.

Then use a timer to monitor System.MouseX and System.MouseY to position the small cursor window under the mouse cursor. If the window is not perfectly aligned to the cursor, it will probably look kind of odd, like seeing cursor double. But when the screen is grabbed, only the cursor window will show.

The thorny thing is, if the app loses front, the false cursor will stop moving. So that cannot be used to grab the screen while clicking elsewhere.

Another solution is to use System.MouseX and Y to DrawPicture the cursor in the grabbed image at the proper place.

Here’s an updated version that asks Windows to draw the current cursor icon into the picture at the current mouse coordinates. In my testing it’s a few pixels off, though:

[code]Function CaptureRect(X As Integer, Y As Integer, Width As Integer, Height As Integer) As Picture
'Performs a screen capture on the specified screen rectangle.
#If TargetWin32 Then
Declare Function GetDesktopWindow Lib “User32” () As Integer
Declare Function GetDC Lib “User32” (HWND As Integer) As Integer
Declare Function BitBlt Lib “GDI32” (DCdest As Integer, xDest As Integer, yDest As Integer, Width As Integer, _
Height As Integer, DCdource As Integer, xSource As Integer, ySource As Integer, rasterOp As Integer) As Boolean
Declare Function ReleaseDC Lib “User32” (HWND As Integer, DC As Integer) As Integer
Const SRCCOPY = &h00CC0020
Const CAPTUREBLT = &h40000000

If Width = 0 Or Height = 0 Then Return Nil
Dim screenCap As Picture = New Picture(Width, Height, 24)
Dim HWND As Integer = GetDesktopWindow()
Dim SourceDC As Integer = GetDC(HWND)
Dim DestDC As Integer = screenCap.Graphics.Handle(screenCap.Graphics.HandleTypeHDC)
Call BitBlt(DestDC, 0, 0, Width, Height, SourceDC, X, Y, SRCCOPY Or CAPTUREBLT)
Call ReleaseDC(HWND, SourceDC)

//ADDED CODE STARTS HERE
Declare Function GetCursorInfo Lib "User32" (CursorInfo As Ptr) As Boolean
Declare Function DrawIcon Lib "User32" (hDC As Integer, X As Integer, Y As Integer, hIcon As Integer) As Boolean
Const DI_MASK = &H1
Dim cursorinfo As New MemoryBlock(20) ' A CURSORINFO structure
cursorinfo.Int32Value(0) = cursorinfo.Size
If Not GetCursorInfo(cursorinfo) Then Return Nil
Dim hCursor As Integer = cursorinfo.Int32Value(8) ' current cursor handle
If Not DrawIcon(DestDC, System.MouseX - X, System.MouseY - Y, hCursor) Then Return Nil
//End added part

Return screenCap

#Endif
End Function
[/code]

[quote=224590:@Axel Schneider]selected Window

dim mshell as new Shell
mshell.Execute “screencapture -iW -o -c”[/quote]

Can this be done non-interactively, (automatically, since the window would have already been selected)?
I have not seen that on the manpage.

Thanks.

Lennox

Unfortunately the clipboard is bugged in the Windows version of Xojo2017, pasting the image to a pictureviewer only shows a white rectangle. I tried it in Xojo 2016r2.1 and there it works just fine.

<https://xojo.com/issue/48844>

The case is set to Private or do not exists.

it’s only for beta testers