Jump to content

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

GdiPlus_SaveImageToBuffer()


  • Please log in to reply
8 replies to this topic
SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
GdiPlus_SaveImageToBuffer() returns the size of created data buffer.

Tested in XP SP3 32-Bit with AHK 1.0 and AHK_Lw 1.1
  • Parameters:

    Image : A handle to either GDI or GDIPlus Bitmap.
    ICON is not supported owing to complex code required for Alpha transparency.

    Buffer : Variable to hold raw image data.

    Type : BMP DIB RLE JPG JPEG JPE JFIF GIF TIF TIFF PNG.
    JPG is default

    Quality : For JPG, pass a value from 0 to 100. For TIF pass 6, only if you required uncompressed image.
    If a value is not passed, default compression will be applied

    Note: GDI+ needs to be initialized before calling this function. I presume you already have gdip.ahk in UserLib
Thanks to Sean happy.png
 
 
GdiPlus_SaveImageToBuffer( Image, ByRef Buffer, Type="JPG", nQuality="" ) {


/*
   Code adapted by SKAN for Wicked, Created / Last Modified:  09-Oct-2012
                http://www.autohotkey.com/community/viewtopic.php?&t=93472


   Credit Sean: Screen Capture with Transparent Windows and Mouse Cursor
                http://www.autohotkey.com/community/viewtopic.php?t=18146
                http://www.autohotkey.com/community/viewtopic.php?p=408135#p408135


                How to convert Image data (JPEG/PNG/GIF) to hBITMAP ?
                http://www.autohotkey.com/community/viewtopic.php?p=147029#p147029
*/


 ; Test for GDI / GDIPlus bitmap
 If DllCall( "GetObjectType", UInt,Image ) = 7
    DllCall( "gdiplus\GdipCreateBitmapFromHBITMAP", UInt,Image, UInt,0, UIntP,pBM )
 Else If DllCall( "gdiplus\GdipGetImageType", UInt,Image, UIntP,ErrorLevel ) = 0
      pBM := Image
 Else Return 0


 ; Determine Encoder CLSID
 DllCall( "gdiplus\GdipGetImageEncodersSize", UIntP,nCount, UIntP,nSize )
 VarSetCapacity( ci,nSize )
 DllCall( "gdiplus\GdipGetImageEncoders", UInt,nCount, UInt,nSize, UInt,&ci )


 Loop %nCount% {
  If ( ( pStr := NumGet( ci, Ix := 76 * (A_Index-1) + 44 ) ) && A_IsUnicode )
     Extns := DllCall( "MulDiv", UInt,pStr, Int,1, Int,1, Str )
  Else
     VarSetCapacity( Extns, nSize := DllCall( "lstrlenW", UInt,pStr ) + 1, 0 )
   , DllCall( "WideCharToMultiByte", UInt,0, UInt,0, UInt,pStr, Int,-1, Str,Extns
                                   , Int,nSize, Int,0, Int,0 )
  If ( ( Found := InStr( Extns, "*." Type ) ) && ( pEnc := &ci + Ix - 44 ) )
     Break
} IfLess, Found, 1, Return 0




 ; Determine Encoder Parameters in case of JPG/TIF
 pEncP := 0
 If ( InStr( ".JPG.JPEG.JPE.JFIF", "." . Type ) && nQuality <> "" ) {
  nQuality := ( nQuality < 0 || nQuality > 100 ) ? 75 : nQuality
  DllCall( "gdiplus\GdipGetEncoderParameterListSize", UInt,pBM, UInt,pEnc, UIntP,nSz )
  VarSetCapacity( pi,nSz,0 )
  DllCall( "gdiplus\GdipGetEncoderParameterList", UInt,pBM, UInt,pEnc, Int,nSz, UInt,&pi )
  Loop % NumGet(pi)
   If ( NumGet( pi, 28*(A_Index-1)+20 ) = 1 && NumGet( pi, 28*(A_Index-1)+24 ) = 6 ) {
        pEncP := &pi + 28*(A_Index-1)
        NumPut( nQuality, NumGet( NumPut( 4, NumPut( 1,pEncP+0 ) + 20 ) ) )
        Break
   }
 }
 Else If ( InStr( ".TIF.TIFF", "." . Type ) && nQuality <> "" ) {
  nQuality := ( nQuality < 2 || nQuality > 6 ) ? 6 : nQuality
  DllCall( "gdiplus\GdipGetEncoderParameterListSize", UInt,pBM, UInt,pEnc, UIntP,nSz )
  VarSetCapacity( pi,nSz,0 )
  DllCall( "gdiplus\GdipGetEncoderParameterList", UInt,pBM, UInt,pEnc, Int,nSz, UInt,&pi )
  Loop % NumGet(pi)
   If ( NumGet( pi,28*(A_Index-1)+20 )=5 && NumGet( NumGet( pi,28*(A_Index-1)+28) )=2 ) {
        pEncP := &pi + 28*(A_Index-1)
        NumPut( nQuality, NumGet( NumPut( 1, NumPut( 1,pEncP+0) + 16 ) + 4 ) )
        Break
   }
 }


 ; Save Image to Stream and copy it to Buffer
 DllCall( "ole32\CreateStreamOnHGlobal", UInt,0, Int,1, UIntP,pStream )
 DllCall( "gdiplus\GdipSaveImageToStream", UInt,pBM, UInt,pStream, UInt,pEnc, UInt,pEncP )
 DllCall( "gdiplus\GdipDisposeImage", UInt,pBM )
 DllCall( "ole32\GetHGlobalFromStream", UInt,pStream, UIntP,hData )
 pData := DllCall( "GlobalLock", UInt,hData )
 nSize := DllCall( "GlobalSize", UInt,pData )
 VarSetCapacity( Buffer, nSize, 0 )
 DllCall( "RtlMoveMemory", UInt,&Buffer, UInt,pData, UInt,nSize )
 DllCall( "GlobalUnlock", UInt,hData )
 DllCall( NumGet( NumGet( 1*pStream ) + 8 ), UInt,pStream )
 DllCall( "GlobalFree", UInt,hData )
Return nSize
}
 


The older counter part:

GDIPlus_hBitmapFromBuffer()
 
 
 
 
GDIPlus_hBitmapFromBuffer( ByRef Buffer, nSize ) { ;  Last Modifed : 21-Jun-2011
; Adapted version by SKAN www.autohotkey.com/forum/viewtopic.php?p=383863#383863
; Original code   by Sean www.autohotkey.com/forum/viewtopic.php?p=147029#147029
 hData := DllCall("GlobalAlloc", UInt,2, UInt,nSize )
 pData := DllCall("GlobalLock",  UInt,hData )
 DllCall( "RtlMoveMemory", UInt,pData, UInt,&Buffer, UInt,nSize )
 DllCall( "GlobalUnlock" , UInt,hData )
 DllCall( "ole32\CreateStreamOnHGlobal", UInt,hData, Int,True, UIntP,pStream )
 DllCall( "gdiplus\GdipCreateBitmapFromStream",  UInt,pStream, UIntP,pBitmap )
 DllCall( "gdiplus\GdipCreateHBITMAPFromBitmap", UInt,pBitmap, UIntP,hBitmap, UInt
,DllCall( "ntdll\RtlUlongByteSwap",UInt
,DllCall( "GetSysColor", Int,15 ) <<8 ) | 0xFF000000 )
 DllCall( "gdiplus\GdipDisposeImage", UInt,pBitmap )
 DllCall( NumGet( NumGet(1*pStream)+8 ), UInt,pStream ) ; IStream::Release
Return hBitmap
}
On a related note:
MiniZIP.ahk - AutoHotkey Wrapper for minizip.dll
With MZ_ZipAddMem() you may write 'buffer converted screenshots' directly into a password protected zip file.
kWo4Lk1.png

Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
This man is a God-send. Thank you, SKAN!

I've begun completely rewriting my script from scratch using classes, but will be sure to tell you how it works! I'll plug it into one of the older versions and get back to you! :D!

3nL8f.png


Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008

A few are probably wondering what the uses of these functions are, so I'll post my reason for needing them... And they work perfect for it, which is always expected from SKAN's work!

I needed to send a 256x256 captured image from one computer to another using a server as the middle-man. For security reasons, this server will not allow file uploads. It'll only accept text/plain and application/x-www-form-urlencoded.

So, my script:

  • Captures a bitmap
  • Saves that bitmap to buffer
  • Encode the buffer to Base64 using SKAN's Base64Enc() and Base64Dec()
  • Upload the Base64
  • If a new bitmap has been uploaded, the scripts on the other PCs:
  • Download the new Base64 data
  • Decode the Base64
  • GDIPlus_hBitmapFromBuffer()
  • Draw the updated bitmap

A huge thank-you to SKAN! You've made this a lot easier then I thought it'd be. Hopefully others find it just as useful!

TL/DR: It's great for sharing screenshots and images between computers without requiring a file transfer!


3nL8f.png


SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

You've made this a lot easier then I thought it'd be.


Now I am glad.. I was feeling a bit guilty for the delay.

Le____
  • Members
  • 4 posts
  • Last active: Feb 09 2019 03:19 PM
  • Joined: 17 Oct 2014

Exactly what i was looking for, Gracias!



Skrell
  • Members
  • 384 posts
  • Last active: Jul 07 2016 05:03 PM
  • Joined: 23 Aug 2011

I'm a GDI virgin but was wondering if a good use of this function would be to save a screenshot of a window to memory and then draw it somewhere on teh screen (like other various window preview scripts work)?   If the answer is yes, would someone mind providing a short tutorial of this?



noname
  • Members
  • 650 posts
  • Last active:
  • Joined: 12 Nov 2011

It is very easy if you use Tic's gdip.ahk library.

 

example:

#include *i gdip.ahk ;download here http://www.autohotkey.com/forum/topic32238.html 

onexit bye

If !pToken := Gdip_Startup()
{
   MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
   ExitApp
}
Gui, 1:  -Caption +E0x80000 +LastFound +OwnDialogs +Owner +hwndhwnd +alwaysontop
Gui, 1: Show, NA 

w:=a_screenwidth//4
h:=a_screenheight//4

hbm := CreateDIBSection(w,h)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hbm)
pGraphics := Gdip_GraphicsFromHDC(hdc)


Gdip_SetInterpolationMode(pGraphics,7)

pBitmap:=Gdip_BitmapFromScreen()
Gdip_DrawImage(pGraphics, pBitmap, 0, 0, w, h)
Gdip_DisposeImage(pBitmap)

UpdateLayeredWindow(hwnd, hdc,(a_screenwidth-w)//2,(a_screenheight-h)//2,w,h)

OnMessage(0x201,"WM_LBUTTONDOWN")
return

WM_LBUTTONDOWN(wParam,lParam,msg,hwnd){
PostMessage, 0xA1, 2 
}

esc::
bye:

SelectObject(hdc, obm)
DeleteObject(hbm)
DeleteDC(hdc)
Gdip_DeleteGraphics(pGraphics)
Gdip_Shutdown(pToken)
ExitApp



winXP  and ahk unicode


Skrell
  • Members
  • 384 posts
  • Last active: Jul 07 2016 05:03 PM
  • Joined: 23 Aug 2011

 

It is very easy if you use Tic's gdip.ahk library.

 

example:

#include *i gdip.ahk ;download here http://www.autohotkey.com/forum/topic32238.html 

onexit bye

If !pToken := Gdip_Startup()
{
   MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
   ExitApp
}
Gui, 1:  -Caption +E0x80000 +LastFound +OwnDialogs +Owner +hwndhwnd +alwaysontop
Gui, 1: Show, NA 

w:=a_screenwidth//4
h:=a_screenheight//4

hbm := CreateDIBSection(w,h)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hbm)
pGraphics := Gdip_GraphicsFromHDC(hdc)


Gdip_SetInterpolationMode(pGraphics,7)

pBitmap:=Gdip_BitmapFromScreen()
Gdip_DrawImage(pGraphics, pBitmap, 0, 0, w, h)
Gdip_DisposeImage(pBitmap)

UpdateLayeredWindow(hwnd, hdc,(a_screenwidth-w)//2,(a_screenheight-h)//2,w,h)

OnMessage(0x201,"WM_LBUTTONDOWN")
return

WM_LBUTTONDOWN(wParam,lParam,msg,hwnd){
PostMessage, 0xA1, 2 
}

esc::
bye:

SelectObject(hdc, obm)
DeleteObject(hbm)
DeleteDC(hdc)
Gdip_DeleteGraphics(pGraphics)
Gdip_Shutdown(pToken)
ExitApp


I assume this reply was in response to my question in which case THANK YOU i will play with this when i get home!! :)



Skrell
  • Members
  • 384 posts
  • Last active: Jul 07 2016 05:03 PM
  • Joined: 23 Aug 2011

 

It is very easy if you use Tic's gdip.ahk library.

 

example:



I assume this reply was in response to my question in which case THANK YOU i will play with this when i get home!! :)