Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Screen Capture using only AHK. No 3rd party software required.


  • Please log in to reply
10 replies to this topic
Cruncher1
  • Members
  • 104 posts
  • Last active: Oct 05 2017 05:11 PM
  • Joined: 21 Feb 2012

This script takes a screen shot (screen capture) and saves it as a jpg (png, bmp) in a folder.

 

I had been searching for this functionality for some time and had been misled by some posts on the AHK forums into believing that this was not something AHK could do without 3rd party software. Then, I discovered Gdip.ahk which solves this problem. However, Gdip.ahk is a very large library and contains many other features not required for a screen capture. So, I simply edited out everything from Gdip that was not required for a screenshot.

 

All credit for this script belongs to others (Tariq Porter). I did not write a single line of the code below. I only removed the thousand(s) of lines of code that were not required for taking a screenshot. I post it here because I am probably not the only person who wanted this functionality in an AHK-only script.

 

Search Terms: Screenshot, Screencapture, screen shot, screen capture, 

Full Gdip.ahk: https://ahknet.autoh...m/~tic/Gdip.ahk

Gdip tutorial: http://www.autohotke...ary-145-by-tic/

 

CODE:

;
;################################################################################################
;        Takes a screenshot, names it and puts it in folder called "ScreenShots"
;This entire script is just an edit of Gdip standard library v1.45 by tic (Tariq Porter) 07/09/11
;
;          Gdip code available from: http://www.autohotkey.net/~tic/Gdip.ahk
;   Gdip tutorial: http://www.autohotkey.com/board/topic/29449-gdi-standard-library-145-by-tic/
;################################################################################################
;################################################################################################


pToken := Gdip_Startup()
OnExit, shutdown

folderPath := A_ScriptDir "\ScreenShots\"
fileName :=  A_YYYY "-" A_MM "-" A_DD "-" A_Hour "-" A_Min "-" A_Sec ".jpg"
;;NOTE: other formats are supported, just replace "jpg" with "png" or another format in the fileName.

CaptureScreen:
	pBitmap := Gdip_BitmapFromScreen()
	saveFileTo := folderPath fileName                   
	Gdip_SaveBitmapToFile(pBitmap, saveFileTo)
	Gdip_DisposeImage(pBitmap)
	return

shutdown:
	Gdip_Shutdown(pToken)
	Exitapp
	return


;################################################################################################
; All that follows are copied from the Gdip standard library v1.45 by tic (Tariq Porter) 07/09/11
;
;################################################################################################
;################################################################################################
; Function				Gdip_BitmapFromScreen
; Description			Gets a gdi+ bitmap from the screen
;
; Screen				0 = All screens
;						Any numerical value = Just that screen
;						x|y|w|h = Take specific coordinates with a width and height
; Raster				raster operation code
;
; return      			If the function succeeds, the return value is a pointer to a gdi+ bitmap
;						-1:		one or more of x,y,w,h not passed properly
;
; notes					If no raster operation is specified, then SRCCOPY is used to the returned bitmap

Gdip_BitmapFromScreen(Screen=0, Raster="")
{
	if (Screen = 0)
	{
		Sysget, x, 76
		Sysget, y, 77	
		Sysget, w, 78
		Sysget, h, 79
	}
	else if (SubStr(Screen, 1, 5) = "hwnd:")
	{
		Screen := SubStr(Screen, 6)
		if !WinExist( "ahk_id " Screen)
			return -2
		WinGetPos,,, w, h, ahk_id %Screen%
		x := y := 0
		hhdc := GetDCEx(Screen, 3)
	}
	else if (Screen&1 != "")
	{
		Sysget, M, Monitor, %Screen%
		x := MLeft, y := MTop, w := MRight-MLeft, h := MBottom-MTop
	}
	else
	{
		StringSplit, S, Screen, |
		x := S1, y := S2, w := S3, h := S4
	}

	if (x = "") || (y = "") || (w = "") || (h = "")
		return -1

	chdc := CreateCompatibleDC(), hbm := CreateDIBSection(w, h, chdc), obm := SelectObject(chdc, hbm), hhdc := hhdc ? hhdc : GetDC()
	BitBlt(chdc, 0, 0, w, h, hhdc, x, y, Raster)
	ReleaseDC(hhdc)
	
	pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
	SelectObject(chdc, obm), DeleteObject(hbm), DeleteDC(hhdc), DeleteDC(chdc)
	return pBitmap
}
;#####################################################################################

; Function:     		Gdip_SaveBitmapToFile
; Description:  		Saves a bitmap to a file in any supported format onto disk
;   
; pBitmap				Pointer to a bitmap
; sOutput      			The name of the file that the bitmap will be saved to. Supported extensions are: .BMP,.DIB,.RLE,.JPG,.JPEG,.JPE,.JFIF,.GIF,.TIF,.TIFF,.PNG
; Quality      			If saving as jpg (.JPG,.JPEG,.JPE,.JFIF) then quality can be 1-100 with default at maximum quality
;
; return      			If the function succeeds, the return value is zero, otherwise:
;						-1 = Extension supplied is not a supported file format
;						-2 = Could not get a list of encoders on system
;						-3 = Could not find matching encoder for specified file format
;						-4 = Could not get WideChar name of output file
;						-5 = Could not save file to disk
;
; notes					This function will use the extension supplied from the sOutput parameter to determine the output format

Gdip_SaveBitmapToFile(pBitmap, sOutput, Quality=75)
{
	SplitPath, sOutput,,, Extension
	if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
		return -1
	Extension := "." Extension

	DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", nCount, "uint*", nSize)
	VarSetCapacity(ci, nSize)
	DllCall("gdiplus\GdipGetImageEncoders", "uint", nCount, "uint", nSize, "uint", &ci)
	if !(nCount && nSize)
		return -2
   
	Loop, %nCount%
	{
		Location := NumGet(ci, 76*(A_Index-1)+44)
		if !A_IsUnicode
		{
			nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "uint", 0, "int",  0, "uint", 0, "uint", 0)
			VarSetCapacity(sString, nSize)
			DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "str", sString, "int", nSize, "uint", 0, "uint", 0)
			if !InStr(sString, "*" Extension)
				continue
		}
		else
		{
			nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "uint", 0, "int",  0, "uint", 0, "uint", 0)
			sString := ""
			Loop, %nSize%
				sString .= Chr(NumGet(Location+0, 2*(A_Index-1), "char"))
			if !InStr(sString, "*" Extension)
				continue
		}
		pCodec := &ci+76*(A_Index-1)
		break
	}
	if !pCodec
		return -3

	if (Quality != 75)
	{
		Quality := (Quality < 0) ? 0 : (Quality > 100) ? 100 : Quality
		if Extension in .JPG,.JPEG,.JPE,.JFIF
		{
			DllCall("gdiplus\GdipGetEncoderParameterListSize", "uint", pBitmap, "uint", pCodec, "uint*", nSize)
			VarSetCapacity(EncoderParameters, nSize, 0)
			DllCall("gdiplus\GdipGetEncoderParameterList", "uint", pBitmap, "uint", pCodec, "uint", nSize, "uint", &EncoderParameters)
			Loop, % NumGet(EncoderParameters)      ;%
			{
				if (NumGet(EncoderParameters, (28*(A_Index-1))+20) = 1) && (NumGet(EncoderParameters, (28*(A_Index-1))+24) = 6)
				{
				   p := (28*(A_Index-1))+&EncoderParameters
				   NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20)))
				   break
				}
			}      
	  }
	}

	if !A_IsUnicode
	{
		nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &sOutput, "int", -1, "uint", 0, "int", 0)
		VarSetCapacity(wOutput, nSize*2)
		DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, "uint", &sOutput, "int", -1, "uint", &wOutput, "int", nSize)
		VarSetCapacity(wOutput, -1)
		if !VarSetCapacity(wOutput)
			return -4
		E := DllCall("gdiplus\GdipSaveImageToFile", "uint", pBitmap, "uint", &wOutput, "uint", pCodec, "uint", p ? p : 0)
	}
	else
		E := DllCall("gdiplus\GdipSaveImageToFile", "uint", pBitmap, "uint", &sOutput, "uint", pCodec, "uint", p ? p : 0)
	return E ? -5 : 0
}

;#####################################################################################

Gdip_DisposeImage(pBitmap)
{
   return DllCall("gdiplus\GdipDisposeImage", "uint", pBitmap)
}

;#####################################################################################

; DCX_CACHE = 0x2
; DCX_CLIPCHILDREN = 0x8
; DCX_CLIPSIBLINGS = 0x10
; DCX_EXCLUDERGN = 0x40
; DCX_EXCLUDEUPDATE = 0x100
; DCX_INTERSECTRGN = 0x80
; DCX_INTERSECTUPDATE = 0x200
; DCX_LOCKWINDOWUPDATE = 0x400
; DCX_NORECOMPUTE = 0x100000
; DCX_NORESETATTRS = 0x4
; DCX_PARENTCLIP = 0x20
; DCX_VALIDATE = 0x200000
; DCX_WINDOW = 0x1

GetDCEx(hwnd, flags=0, hrgnClip=0)
{
    return DllCall("GetDCEx", "uint", hwnd, "uint", hrgnClip, "int", flags)
}

;#####################################################################################

; Function				CreateCompatibleDC
; Description			This function creates a memory device context (DC) compatible with the specified device
;
; hdc					Handle to an existing device context					
;
; return				returns the handle to a device context or 0 on failure
;
; notes					If this handle is 0 (by default), the function creates a memory device context compatible with the application's current screen

CreateCompatibleDC(hdc=0)
{
   return DllCall("CreateCompatibleDC", "uint", hdc)
}

;#####################################################################################

; Function				CreateDIBSection
; Description			The CreateDIBSection function creates a DIB (Device Independent Bitmap) that applications can write to directly
;
; w						width of the bitmap to create
; h						height of the bitmap to create
; hdc					a handle to the device context to use the palette from
; bpp					bits per pixel (32 = ARGB)
; ppvBits				A pointer to a variable that receives a pointer to the location of the DIB bit values
;
; return				returns a DIB. A gdi bitmap
;
; notes					ppvBits will receive the location of the pixels in the DIB

CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0)
{
	hdc2 := hdc ? hdc : GetDC()
	VarSetCapacity(bi, 40, 0)
	NumPut(w, bi, 4), NumPut(h, bi, 8), NumPut(40, bi, 0), NumPut(1, bi, 12, "ushort"), NumPut(0, bi, 16), NumPut(bpp, bi, 14, "ushort")
	hbm := DllCall("CreateDIBSection", "uint" , hdc2, "uint" , &bi, "uint" , 0, "uint*", ppvBits, "uint" , 0, "uint" , 0)

	if !hdc
		ReleaseDC(hdc2)
	return hbm
}
;#####################################################################################

; Function				SelectObject
; Description			The SelectObject function selects an object into the specified device context (DC). The new object replaces the previous object of the same type
;
; hdc					Handle to a DC
; hgdiobj				A handle to the object to be selected into the DC
;
; return				If the selected object is not a region and the function succeeds, the return value is a handle to the object being replaced
;
; notes					The specified object must have been created by using one of the following functions
;						Bitmap - CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBitmap, CreateDIBSection (A single bitmap cannot be selected into more than one DC at the same time)
;						Brush - CreateBrushIndirect, CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush
;						Font - CreateFont, CreateFontIndirect
;						Pen - CreatePen, CreatePenIndirect
;						Region - CombineRgn, CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn, CreateRectRgn, CreateRectRgnIndirect
;
; notes					If the selected object is a region and the function succeeds, the return value is one of the following value
;
; SIMPLEREGION			= 2 Region consists of a single rectangle
; COMPLEXREGION			= 3 Region consists of more than one rectangle
; NULLREGION			= 1 Region is empty

SelectObject(hdc, hgdiobj)
{
   return DllCall("SelectObject", "uint", hdc, "uint", hgdiobj)
}
;#####################################################################################

; Function				GetDC
; Description			This function retrieves a handle to a display device context (DC) for the client area of the specified window.
;						The display device context can be used in subsequent graphics display interface (GDI) functions to draw in the client area of the window. 
;
; hwnd					Handle to the window whose device context is to be retrieved. If this value is NULL, GetDC retrieves the device context for the entire screen					
;
; return				The handle the device context for the specified window's client area indicates success. NULL indicates failure

GetDC(hwnd=0)
{
	return DllCall("GetDC", "uint", hwnd)
}
;#####################################################################################

; Function				BitBlt
; Description			The BitBlt function performs a bit-block transfer of the color data corresponding to a rectangle 
;						of pixels from the specified source device context into a destination device context.
;
; dDC					handle to destination DC
; dx					x-coord of destination upper-left corner
; dy					y-coord of destination upper-left corner
; dw					width of the area to copy
; dh					height of the area to copy
; sDC					handle to source DC
; sx					x-coordinate of source upper-left corner
; sy					y-coordinate of source upper-left corner
; Raster				raster operation code
;
; return				If the function succeeds, the return value is nonzero
;
; notes					If no raster operation is specified, then SRCCOPY is used, which copies the source directly to the destination rectangle
;
; BLACKNESS				= 0x00000042
; NOTSRCERASE			= 0x001100A6
; NOTSRCCOPY			= 0x00330008
; SRCERASE				= 0x00440328
; DSTINVERT				= 0x00550009
; PATINVERT				= 0x005A0049
; SRCINVERT				= 0x00660046
; SRCAND				= 0x008800C6
; MERGEPAINT			= 0x00BB0226
; MERGECOPY				= 0x00C000CA
; SRCCOPY				= 0x00CC0020
; SRCPAINT				= 0x00EE0086
; PATCOPY				= 0x00F00021
; PATPAINT				= 0x00FB0A09
; WHITENESS				= 0x00FF0062
; CAPTUREBLT			= 0x40000000
; NOMIRRORBITMAP		= 0x80000000

BitBlt(ddc, dx, dy, dw, dh, sdc, sx, sy, Raster="")
{
	return DllCall("gdi32\BitBlt", "uint", dDC, "int", dx, "int", dy, "int", dw, "int", dh
	, "uint", sDC, "int", sx, "int", sy, "uint", Raster ? Raster : 0x00CC0020)
}

;#####################################################################################

; Function				ReleaseDC
; Description			This function releases a device context (DC), freeing it for use by other applications. The effect of ReleaseDC depends on the type of device context
;
; hdc					Handle to the device context to be released
; hwnd					Handle to the window whose device context is to be released
;
; return				1 = released
;						0 = not released
;
; notes					The application must call the ReleaseDC function for each call to the GetWindowDC function and for each call to the GetDC function that retrieves a common device context
;						An application cannot use the ReleaseDC function to release a device context that was created by calling the CreateDC function; instead, it must use the DeleteDC function. 

ReleaseDC(hdc, hwnd=0)
{
   return DllCall("ReleaseDC", "uint", hwnd, "uint", hdc)
}

;#####################################################################################

Gdip_CreateBitmapFromHBITMAP(hBitmap, Palette=0)
{
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "uint", hBitmap, "uint", Palette, "uint*", pBitmap)
	return pBitmap
}
;#####################################################################################

; Function				DeleteObject
; Description			This function deletes a logical pen, brush, font, bitmap, region, or palette, freeing all system resources associated with the object
;						After the object is deleted, the specified handle is no longer valid
;
; hObject				Handle to a logical pen, brush, font, bitmap, region, or palette to delete
;
; return				Nonzero indicates success. Zero indicates that the specified handle is not valid or that the handle is currently selected into a device context

DeleteObject(hObject)
{
   return DllCall("DeleteObject", "uint", hObject)
}
;#####################################################################################

; Function				DeleteDC
; Description			The DeleteDC function deletes the specified device context (DC)
;
; hdc					A handle to the device context
;
; return				If the function succeeds, the return value is nonzero
;
; notes					An application must not delete a DC whose handle was obtained by calling the GetDC function. Instead, it must call the ReleaseDC function to free the DC

DeleteDC(hdc)
{
   return DllCall("DeleteDC", "uint", hdc)
}

;#####################################################################################

Gdip_Startup()
{
	if !DllCall("GetModuleHandle", "str", "gdiplus")
		DllCall("LoadLibrary", "str", "gdiplus")
	VarSetCapacity(si, 16, 0), si := Chr(1)
	DllCall("gdiplus\GdiplusStartup", "uint*", pToken, "uint", &si, "uint", 0)
	return pToken
}

;#####################################################################################

Gdip_Shutdown(pToken)
{
	DllCall("gdiplus\GdiplusShutdown", "uint", pToken)
	if hModule := DllCall("GetModuleHandle", "str", "gdiplus")
		DllCall("FreeLibrary", "uint", hModule)
	return 0
}

 

 



paulinColorado
  • Members
  • 3 posts
  • Last active: Jul 08 2015 05:41 PM
  • Joined: 03 Jul 2007

Didn't work for me. 

 

===>  SOLVED!  I had an old instance of GDIplus.dll in ahk dir, and once removed, it worked!

 

Paul

 

=====  PROBLEM DESCRIPTION

 

I made a few changes to try all output file types in succession and all formats failed with errorcode=-3

 

The  failure was in

Gdip_SaveBitmapToFile(pBitmap, sOutput, Quality=75)

 

-3 = Could not find matching encoder for specified file format

 

Could I have some help here?  Running 64bit Unicode version

 

 

===>  Also tried Under ANSII Version and Got Same failure code:

brief code dump:

164: if !pCodec  
165: Return,-3

 

I'm using latest version of AHK, Windows 7

 

Any help/ideas?

 

Thx,

Paul



atnbueno
  • Members
  • 91 posts
  • Last active: Feb 16 2016 07:04 PM
  • Joined: 24 Mar 2007

Paul--

 

IIRC there are two versions of Gdip.ahk, one for 32-bit AHK and another one for 64-bit AHK. tic planned to combine them but I haven't seen it done.

 

Forgive my curiosity but is there any particular reason to work with the 64-bit version of AHK?


Regards,
Antonio

A v i
  • Members
  • 1323 posts
  • Last active: Nov 14 2015 06:56 PM
  • Joined: 30 Jan 2013

Hey,

Won't you all will like to capture whole screen as well as selected part of the screen and resize it if needed on the fly.

And that too with only AHK.

 

Try my Extreme Screen Clipper

 

@antonio

Rseeding91 has made an all-in-one version of GDIP.ahk for all AHK formats. I currently dont have the link. Try searching him in members and then seeing his Signature. His signature has the link (As far as I remember)

 

Added:

 

And one more thing , guys . some GDIP scripts fail to work on UncodeX64 AHK_L version (as my Extreme Screen Clipper), for that use AHK_L 32-bit ANSI.


Now a CS Undergrad. | My WebsiteAutohotkey Scripts | Softwares

Telegram me : @aviaryan


atnbueno
  • Members
  • 91 posts
  • Last active: Feb 16 2016 07:04 PM
  • Joined: 24 Mar 2007

Thanks for the clue, A v i. I've found it at https://ahknet.autoh...ll/Gdip_All.ahk

 

One question (and sorry to Cruncher1 for the slight detour): if someone has problems with AHK U64, why recommend AHK A32 (instead of AHK U32)? If the architecture is the problem, why suggest changing also the encoding?


Regards,
Antonio

A v i
  • Members
  • 1323 posts
  • Last active: Nov 14 2015 06:56 PM
  • Joined: 30 Jan 2013

@antonio

 

The problem is the encoding and not the architecture . You see, ANSI has only 32-bit version, no 64-bit.

I know I should not have mentioned ahk_l ANSI 32-bit but that's like a habit, Sorry there !

 

I dont know whats the problem with Encoding,no doubt there are topics in Support about them.


Now a CS Undergrad. | My WebsiteAutohotkey Scripts | Softwares

Telegram me : @aviaryan


BrandonHotkey
  • Members
  • 691 posts
  • Last active: Oct 21 2015 09:41 PM
  • Joined: 21 May 2012

I have found problem when I tried to create screenshot of part of screen in game Age Of Kings - The  Conquerors

Screenshot here

http://aok.heavengam...o_theconqs1.jpg

.

It successfully creates the screenshot to clipboard, but in the game it changes background or look of the map floor. So as it is in the link above, the green will change to some other strange colors. Also when there is a water so it changes colors of the pixel. It will return to the original if I switch to Windows and then back to game so the colors are restored. However this obstructs me to use AHK script, which I intended to use to find out my position on map... Is there any AHK trick which can restore the colors without breaking the game?



BrandonHotkey
  • Members
  • 691 posts
  • Last active: Oct 21 2015 09:41 PM
  • Joined: 21 May 2012

Hello, I found which command causes problem in the game:

DllCall("gdiplus\GdiplusShutdown" , "Uint", pToken)

This command probably closes some interface which the game uses. Therefore I would recommend to add voluntary option which will disable shutting gdiplus. In my script I can simply comment the line, but you could add an exception to your script. Otherwise your script is great!

 


Finally I use it without these two lines:
; DllCall("gdiplus\GdiplusShutdown" , "Uint", pToken) ; this was in collition with Age of Empires game graphics
; DllCall("FreeLibrary", "Uint", hGdiPlus) ; This causes crash of script when GDI+ was not shut down - it crashed when I wanted to do next screenshot


Henry
  • Members
  • 6 posts
  • Last active: May 12 2015 03:14 AM
  • Joined: 24 Apr 2015

I am just starting use autohotkey not long ago. I need to take screen shot and save to folder every 1 hour. I've already know how to use setimer, however this script is kind of complex for me to understand now.

 

could anyone help me on how to use this script? I've saved this into a ahk script but didn't know how to use it.

 

Thanks.



siddbudd
  • Members
  • 5 posts
  • Last active: Jul 20 2016 04:32 PM
  • Joined: 02 Feb 2014

I am just starting use autohotkey not long ago. I need to take screen shot and save to folder every 1 hour. I've already know how to use setimer, however this script is kind of complex for me to understand now.

 

could anyone help me on how to use this script? I've saved this into a ahk script but didn't know how to use it.

 

Thanks.

Hi Henry,

 

This script only works if you have a folder called ScreenShots in the same folder as the script (also knows as A_ScriptDir). All you need to do is launch the script and it will take a screenshot and place it in the ScreenShots folder.

 

Best regards,

siddbudd



johnboy
  • New members
  • 1 posts
  • Last active: Jul 14 2015 08:34 PM
  • Joined: 14 Jul 2015

I am new to AHK.. Can you tell me how I can invoke this script.  All I know how to do so far is to call basic script with CTRL J like in the demo.  All I need to do is take a screen grab of a small section of a screen 100x 100 ..  When I try to launch this script it does nothing.