SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
SKAN
Posts: 1619
Joined: 29 Sep 2013, 16:58

SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by SKAN » 04 Sep 2019, 13:54

SavePicture( hBM, sFile )

Note: This function offers limited functionality: JPEG quality is fixed at 75% and transparency will not be preserved for PNG.
Saved file will be a BMP if you pass any file extension other than: BMP, JPG, JPEG, GIF, PNG, TIF, TIFF

Code: Select all

SavePicture(hBM, sFile) {                                            ; By SKAN on D293 @ bit.ly/2krOIc9
Local V,  pBM := VarSetCapacity(V,16,0)>>8,  Ext := LTrim(SubStr(sFile,-3),"."),  E := [0,0,0,0]
Local Enc := 0x557CF400 | Round({"bmp":0, "jpg":1,"jpeg":1,"gif":2,"tif":5,"tiff":5,"png":6}[Ext])
  E[1] := DllCall("gdi32\GetObjectType", "Ptr",hBM ) <> 7
  E[2] := E[1] ? 0 : DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "Ptr",hBM, "UInt",0, "PtrP",pBM)
  NumPut(0x2EF31EF8,NumPut(0x0000739A,NumPut(0x11D31A04,NumPut(Enc+0,V,"UInt"),"UInt"),"UInt"),"UInt")
  E[3] := pBM ? DllCall("gdiplus\GdipSaveImageToFile", "Ptr",pBM, "WStr",sFile, "Ptr",&V, "UInt",0) : 1
  E[4] := pBM ? DllCall("gdiplus\GdipDisposeImage", "Ptr",pBM) : 1
Return E[1] ? 0 : E[2] ? -1 : E[3] ? -2 : E[4] ? -3 : 1  
}
  • ErrorLevel


SavePicture() requires GDI+ initialized prior to calling it.
GDI+ can be Start.Shut with GDIP("Startup") and GDIP("Shutdown")
Thanks to @tmplinshi for a bug report. Now fixed.

Code: Select all

GDIP(C:="Startup") {                                      ; By SKAN on D293 @ bit.ly/2krOIc9
  Static SI:=Chr(!(VarSetCapacity(Si,24,0)>>16)), pToken:=0, hMod:=0, Res:=0, AOK:=0
  If (AOK := (C="Startup" and pToken=0) Or (C<>"Startup" and pToken<>0))  {
      If (C="Startup") {
               hMod := DllCall("LoadLibrary", "Str","gdiplus.dll", "Ptr")
               Res  := DllCall("gdiplus\GdiplusStartup", "PtrP",pToken, "Ptr",&SI, "UInt",0)
      } Else { 
               Res  := DllCall("gdiplus\GdiplusShutdown", "Ptr",pToken)
               DllCall("FreeLibrary", "Ptr",hMod),   hMod:=0,   pToken:=0
   }}  
Return (AOK ? !Res : Res:=0)    
}

Usage example

The cryptic nested NumPut explained

The following script will automatically Save picture (JPEG) when PrintScreen / Alt+PrintScreen is used for screen capture.

Code: Screen capture demo
My Scripts and Functions: V1  V2

tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by tmplinshi » 07 Sep 2019, 00:29

Hi, just a bug report for 64-bit AutoHotkey:

The return type of LoadLibrary function should be Ptr, otherwise the calling to FreeLibrary function would be fail.

Code: Select all

MsgBox % DllCall("FreeLibrary", "Ptr",hMod) ? "success" : "fail"

User avatar
SKAN
Posts: 1619
Joined: 29 Sep 2013, 16:58

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by SKAN » 07 Sep 2019, 03:11

Thank you @tmplinshi :)
Fixed.
My Scripts and Functions: V1  V2

User avatar
danrevella
Posts: 11
Joined: 27 Jan 2016, 05:08

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by danrevella » 03 Jan 2020, 09:41

Hi,
please excuse for boring, I have look at your tool (and also another in fact this post is replicate over), but I am in search of a script who let me capture and save a full windows who is larger then my desktop: f.e my desktop is 1920*1080 but the window I need to capture is 9400*9200, so if i use PrintScreen or Alt-Printscreen, I obtain an image who only show 1920*1080 instead of 9400*9200.
Does exist a possibility to get the full capture window?
Many thanks

User avatar
SKAN
Posts: 1619
Joined: 29 Sep 2013, 16:58

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by SKAN » 03 Jan 2020, 10:50

danrevella wrote:
03 Jan 2020, 09:41
f.e my desktop is 1920*1080 but the window I need to capture is 9400*9200
I don't understand how this is possible?
If I try to resize a given window to be larger than desktop, the window is resized only to the size of desktop.
For example, with single monitor setup sized 1366x768, I am not able to resize notepad window to 6000x4000 ?!

Code: Select all

#NoEnv
#Warn
#SingleInstance, Force

Run Notepad
Winwait ahk_class Notepad
WinMove,,, 0, 0, 6000, 4000
My Scripts and Functions: V1  V2

User avatar
danrevella
Posts: 11
Joined: 27 Jan 2016, 05:08

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by danrevella » 03 Jan 2020, 11:26

It is possible: try this an give any resolution you want to a (resizable) window


; [^ = Ctrl] [+ = Shift] [! = Alt] [# = Win]
;WIN+t hotkey

#t::
WinGet, window, ID, A
InputBox, width, Resize window, Enter width:, , 170, 130
if (width != "")
{
InputBox, height, Resize Window, Enter height:, , 170, 130
}
WinGetTitle, Title, A
MsgBox, The active window is "%Title%".

WinGet, id, , %Title%
Result := DllCall("SetWindowPos", "uint", id, "uint", HWND_TOP, "Int", 0, "Int", 0, "Int", width, "Int", height, "UInt", 0x400)

return


User avatar
SKAN
Posts: 1619
Joined: 29 Sep 2013, 16:58

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by SKAN » 03 Jan 2020, 14:12

danrevella wrote:
03 Jan 2020, 11:26
It is possible: try this an give any resolution you want to a (resizable) window
Thanks. Nice test code. Nitpick: You haven't defined the constant HWND_TOP which should be 0.

Your snippet doesn't work for all apps though. Maybe those apps have message handlers to override the resize.
Works when tested with Notepad and AutoHotkey help. AutoHotkey spy reveals the window size correctly.

I tried resizing AutoHotkey help to 2000x2000 (My screen is 1366x768) and took a snaphot with hBM := hWnd_to_hBmp( WinExist("A") )
and saved it with SavePicture().
The function is unable to blit the title bar correctly, in Windows 7. Yet to try in Windows 10.
Please refer the attachment
Attachments
ahk.jpg
ahk.jpg (211.7 KiB) Viewed 7636 times
My Scripts and Functions: V1  V2

guest3456
Posts: 3477
Joined: 09 Oct 2013, 10:31

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by guest3456 » 03 Jan 2020, 14:13

danrevella wrote:
03 Jan 2020, 11:26
It is possible: try this an give any resolution you want to a (resizable) window


; [^ = Ctrl] [+ = Shift] [! = Alt] [# = Win]
;WIN+t hotkey

#t::
WinGet, window, ID, A
InputBox, width, Resize window, Enter width:, , 170, 130
if (width != "")
{
InputBox, height, Resize Window, Enter height:, , 170, 130
}
WinGetTitle, Title, A
MsgBox, The active window is "%Title%".

WinGet, id, , %Title%
Result := DllCall("SetWindowPos", "uint", id, "uint", HWND_TOP, "Int", 0, "Int", 0, "Int", width, "Int", height, "UInt", 0x400)

return

does not work for me. i tried resizing notepad to 9000 width, and it only resized to approx 4800 width, which spanned my two monitors.

you could try PrintWindow() to get the screenshot


User avatar
danrevella
Posts: 11
Joined: 27 Jan 2016, 05:08

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by danrevella » 03 Jan 2020, 15:22

SKAN wrote:
03 Jan 2020, 14:12
danrevella wrote:
03 Jan 2020, 11:26
It is possible: try this an give any resolution you want to a (resizable) window
Thanks. Nice test code. Nitpick: You haven't defined the constant HWND_TOP which should be 0.

Your snippet doesn't work for all apps though. Maybe those apps have message handlers to override the resize.
Works when tested with Notepad and AutoHotkey help. AutoHotkey spy reveals the window size correctly.

I tried resizing AutoHotkey help to 2000x2000 (My screen is 1366x768) and took a snaphot with hBM := hWnd_to_hBmp( WinExist("A") )
and saved it with SavePicture().
The function is unable to blit the title bar correctly, in Windows 7. Yet to try in Windows 10.
Please refer the attachment
As I told you, I'm a total beginner in AHK, so please may you post your example with a full working code (also with the necessary dependences?
Many thanks

User avatar
danrevella
Posts: 11
Joined: 27 Jan 2016, 05:08

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by danrevella » 03 Jan 2020, 15:24

guest3456 wrote:
03 Jan 2020, 14:13

does not work for me. i tried resizing notepad to 9000 width, and it only resized to approx 4800 width, which spanned my two monitors.

you could try PrintWindow() to get the screenshot
As I told I'm a newbie, may you gentle tell me about PrintWindow(), is it a native function, or is it a library, may you be so kind to give me the necessary code?
Thanks

User avatar
SKAN
Posts: 1619
Joined: 29 Sep 2013, 16:58

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by SKAN » 04 Jan 2020, 03:04

I have to test this in Windows 10.
I'm leaving city and will be back on Monday.
My Scripts and Functions: V1  V2

User avatar
danrevella
Posts: 11
Joined: 27 Jan 2016, 05:08

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by danrevella » 04 Jan 2020, 05:48

you told me:
Thanks. Nice test code. Nitpick: You haven't defined the constant HWND_TOP which should be 0.

So may you give me the correction to my code?
See you next week

jly
Posts: 89
Joined: 30 Sep 2020, 06:06

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by jly » 22 Feb 2022, 01:52

Hello, SKAN:
I get the thumbnail of a file as an HBitmap, add it to a Picture control, and the background of the picture is transparent.
If I save it as a .png file with SavePicture functtion, the background of the image file is black.
How can I make the background of the saved picture transparent?

In the following two figures, the first is the image of the saved png file,
and the second is the image displayed in the picture control.
Attachments
32de79e2_f554_4098_8bf9_b5a58da8a19a.png
32de79e2_f554_4098_8bf9_b5a58da8a19a.png (2.85 KiB) Viewed 4713 times
t01.png
t01.png (2.51 KiB) Viewed 4713 times

User avatar
SKAN
Posts: 1619
Joined: 29 Sep 2013, 16:58

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by SKAN » 22 Feb 2022, 04:10

jly wrote:
22 Feb 2022, 01:52
If I save it as a .png file with SavePicture functtion, the background of the image file is black.
Yes. This function is compact and too limited, and I have mentioned it in OP.
If you need to save PNG with transparency, you may have to opt for one of the GDIP variants available in our forum.
Thanks.

jly
Posts: 89
Joined: 30 Sep 2020, 06:06

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by jly » 22 Feb 2022, 20:21

SKAN wrote:
22 Feb 2022, 04:10
jly wrote:
22 Feb 2022, 01:52
If I save it as a .png file with SavePicture functtion, the background of the image file is black.
Yes. This function is compact and too limited, and I have mentioned it in OP.
If you need to save PNG with transparency, you may have to opt for one of the GDIP variants available in our forum.
Thanks.
OK,thank you very much!

GEOVAN
Posts: 194
Joined: 03 Mar 2022, 11:12

Re: SavePicture() : Save hBitmap as BMP, JPG, GIF, PNG, TIF

Post by GEOVAN » 25 Apr 2024, 15:48

SKAN wrote:
04 Sep 2019, 13:54
SavePicture( hBM, sFile )

Note: This function offers limited functionality: JPEG quality is fixed at 75% and transparency will not be preserved for PNG.
Saved file will be a BMP if you pass any file extension other than: BMP, JPG, JPEG, GIF, PNG, TIF, TIFF

Code: Select all

SavePicture(hBM, sFile) {                                            ; By SKAN on D293 @ bit.ly/2krOIc9
Local V,  pBM := VarSetCapacity(V,16,0)>>8,  Ext := LTrim(SubStr(sFile,-3),"."),  E := [0,0,0,0]
Local Enc := 0x557CF400 | Round({"bmp":0, "jpg":1,"jpeg":1,"gif":2,"tif":5,"tiff":5,"png":6}[Ext])
  E[1] := DllCall("gdi32\GetObjectType", "Ptr",hBM ) <> 7
  E[2] := E[1] ? 0 : DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "Ptr",hBM, "UInt",0, "PtrP",pBM)
  NumPut(0x2EF31EF8,NumPut(0x0000739A,NumPut(0x11D31A04,NumPut(Enc+0,V,"UInt"),"UInt"),"UInt"),"UInt")
  E[3] := pBM ? DllCall("gdiplus\GdipSaveImageToFile", "Ptr",pBM, "WStr",sFile, "Ptr",&V, "UInt",0) : 1
  E[4] := pBM ? DllCall("gdiplus\GdipDisposeImage", "Ptr",pBM) : 1
Return E[1] ? 0 : E[2] ? -1 : E[3] ? -2 : E[4] ? -3 : 1  
}
  • ErrorLevel


SavePicture() requires GDI+ initialized prior to calling it.
GDI+ can be Start.Shut with GDIP("Startup") and GDIP("Shutdown")
Thanks to @tmplinshi for a bug report. Now fixed.

Code: Select all

GDIP(C:="Startup") {                                      ; By SKAN on D293 @ bit.ly/2krOIc9
  Static SI:=Chr(!(VarSetCapacity(Si,24,0)>>16)), pToken:=0, hMod:=0, Res:=0, AOK:=0
  If (AOK := (C="Startup" and pToken=0) Or (C<>"Startup" and pToken<>0))  {
      If (C="Startup") {
               hMod := DllCall("LoadLibrary", "Str","gdiplus.dll", "Ptr")
               Res  := DllCall("gdiplus\GdiplusStartup", "PtrP",pToken, "Ptr",&SI, "UInt",0)
      } Else { 
               Res  := DllCall("gdiplus\GdiplusShutdown", "Ptr",pToken)
               DllCall("FreeLibrary", "Ptr",hMod),   hMod:=0,   pToken:=0
   }}  
Return (AOK ? !Res : Res:=0)    
}

Usage example

The cryptic nested NumPut explained

The following script will automatically Save picture (JPEG) when PrintScreen / Alt+PrintScreen is used for screen capture.

Code: Screen capture demo

Please, how can we modify this wonderful code to get 100% jpg quality instead of 75% ?

Post Reply

Return to “Scripts and Functions (v1)”