SnapShot with specific coordinates

Started by mueer01, August 09, 2021, 07:42:46 AM

Previous topic - Next topic

mueer01

Hello,

I found  the function SnapShot(request) with a good example.
But is it possible to make a Snapshot from specific coordinates?

i.e. MySnapShot(x1, y1, x2, y2)

Regards,
Erhard

td

Never had a reason to perform this task but one approach would be to take the image of the entire desktop and assuming you know the coordinates clip the part you are interested in after performing some coordinate conversion. Maybe consider using WIL CLR hosting with a dotNet assembly to clip the image.

Perhaps other forum members can suggest the best method for clipping the image or a better approach to the problem.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

The Omnibus extender will do the cropping but it has to be in a file.

Jim

td

Or use the dotNet "System.Drawing" assembly:

https://docs.microsoft.com/en-us/dotnet/api/system.drawing.bitmap.clone?view=net-5.0

But your extender most likely requires less of a learning curve for those not initiated into the world of dotNet scripting with WinBatch.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

Here is a quick and dirty example of using the "System.Drawing" assembly to create a clipped bitmap of a screenshot.

Code (winbatch) Select
;; Load needed assembly.
ObjectClrOption('useany', 'System.Drawing')

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Example from the help file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;Takes a bitmap snapshot of the screen and pastes it to the clipboard.
Snapshot(0)
;returns the size of buffer needed for a subsequent BinaryAlloc,
;but doesn't attempt to place the contents of clipboard into a buffer
size=BinaryClipGet(0,8)
;allocates a data buffer
bb=BinaryAlloc(size)
;read file format type CF_DIB
BinaryClipGet(bb,8)
; need to add first 14 bytes to make it
; a BMP file format
bmpdatasize=14
bb2=BinaryAlloc(size + bmpdatasize)
;The characters identifying the bitmap.'BM'
BinaryPokeStr(bb2, 0, "BM")
;Complete file size in bytes.
BinaryPoke4(bb2,2,size + bmpdatasize)
;Reserved
BinaryPoke4(bb2,6,0)
;Data offset
headersize=BinaryPeek4(bb,0)
dataoffset = headersize + bmpdatasize
BinaryPoke4(bb2,10,dataoffset)
BinaryCopy(bb2,bmpdatasize,bb,0,size)
; Note:Moved bitmap file name to a variable.
BmpFile = "c:\temp\screenshot.bmp"
BinaryWrite(bb2,BmpFile)
BinaryFree(bb)
BinaryFree(bb2)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Use the System.Drawing.Bitmap class to create
;; a new image of just part of the screen.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

objBmp = ObjectClrNew('System.Drawing.Bitmap', BmpFile)

bmpH = objBmp.Height()
bmpW = objBmp.Width()

; Take a slice out of the middle
nX = bmpW/4
nY = BmpH/4
nW = nX * 2
nH = nY * 2
objRect =  ObjectClrNew('System.Drawing.Rectangle', nX, nY, nW, nH)
nDontCare = 0
nDontCare = ObjectClrType('System.Drawing.Imaging.PixelFormat', nDontCare )

objCrop = objBmp.Clone(objRect, nDontCare)

Clip =  'C:\temp\Clipped.bmp'
objCrop.Save(Clip)

; Clean up.
objCrop.Dispose()
objBmp.Dispose()

Run('mspaint.exe', Clip)


Interesting enough you can use dotNet to get the screen shot but the WIL ScreenShot function does the job without the additional learning curve.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

stanl

Be nice if you could Sendkey {PRTSC}.....  ;D .

....IFICantBYTE

Search in the tech database... I remember there were dll calls for win32 ways of saving a bmp of the screen via pixel coordinates... getdc .. createcimpatiblebitmap?? Something like that..
Regards,
....IFICantBYTE

Nothing sucks more than that moment during an argument when you realize you're wrong. :)

cssyphus

Jumping in... FWIW, I had to do exactly this today. In the end, I grabbed a small portion of the screen like this (using the freeware gold standard IrfanView with a couple of command-line parameters):


_iviewApp = `C:\Program Files (x86)\IrfanView\i_view32.exe`

run(_iviewApp, `/capture=7=(-360,950,170,22) /title=OBS Rec Status /hide=15`)

timeDelay(5)
winClose(`IrfanView - OBS Rec Status`)


The above grabs a small bit of the screen (170w x 22h - specifically the current Rec/Pause status of OBS Studio) and opens it in an instance of IrfanView sans titlebar, caption, statusbar, menus. Note that it grabs this screenshot from the second monitor, to my left.

The /hide=15 is particularly nice, since that hides every trace of the IrfanView app except the image and window borders. (And, very nicely, IrfanView doesn't remember that setting next time you start it from the start menu - that is, next launch-from-start-menu it will start up as usual, with all that stuff enabled as per normal).

I can then use winPlace() to stick the window wherever I want (again, on mon2) and windowOnTop() to keep it always-visible until I Right-Click to close it from the taskbar (since there's no caption/windowTitle, close X button due to the " /hide=15").


td

Here's a rough approximation of a "pure" dotNet approach:

Code (winbatch) Select
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Pure FCL approach.

;; Load needed assembly.
ObjectClrOption('useany', 'System.Drawing')
Clip =  'C:\temp\Clipped.bmp'

; Take a slice from somewhere on the screen.
nX = WinMetrics(0)/4
nY = WinMetrics(1)/4
nW = nX * 2
nH = nY * 2
Format32bppArgb  = ObjectClrType('System.Drawing.Imaging.PixelFormat', 2498570)
objBmp = ObjectClrNew('System.Drawing.Bitmap', nX, nY, Format32bppArgb )

objGraphics = ObjectClrNew('System.Drawing.Graphics')
memGraphic  = objGraphics.FromImage(objBmp)

; Copy a portion of the screen to a bitmap and save it to a file.
Size =  ObjectClrNew('System.Drawing.Size', nW, nH)
memGraphic.CopyFromScreen(nX, nY, 0, 0, Size)

Clip =  'C:\temp\Clipped.bmp'
objBmp.Save(Clip)

; View the result.
Run('mspaint.exe', Clip)


It could be taken a step farther by having the clipped image drawn in a dotNet form window.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

Quote from: cssyphus on August 15, 2021, 09:43:41 AM
Jumping in... FWIW, I had to do exactly this today. In the end, I grabbed a small portion of the screen like this (using the freeware gold standard IrfanView with a couple of command-line parameters):


_iviewApp = `C:\Program Files (x86)\IrfanView\i_view32.exe`

run(_iviewApp, `/capture=7=(-360,950,170,22) /title=OBS Rec Status /hide=15`)

timeDelay(5)
winClose(`IrfanView - OBS Rec Status`)


The above grabs a small bit of the screen (170w x 22h - specifically the current Rec/Pause status of OBS Studio) and opens it in an instance of IrfanView sans titlebar, caption, statusbar, menus. Note that it grabs this screenshot from the second monitor, to my left.

The /hide=15 is particularly nice, since that hides every trace of the IrfanView app except the image and window borders. (And, very nicely, IrfanView doesn't remember that setting next time you start it from the start menu - that is, next launch-from-start-menu it will start up as usual, with all that stuff enabled as per normal).

I can then use winPlace() to stick the window wherever I want (again, on mon2) and windowOnTop() to keep it always-visible until I Right-Click to close it from the taskbar (since there's no caption/windowTitle, close X button due to the " /hide=15").

Looks like an interesting tool.

The OP never mentions what the end-use for the image is so the benefit of displaying the image is unknown. Also, Windows and WinBatch have several built-in methods of displaying a random bitmap in various contexts.

Any of the methods mentioned in this topic including Snapshot can be used in the process of grabbing part of a second, third, or fourth monitor simply by specifying the coordinance.

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade