Jump to content
Sign in to follow this  
tip

GDI+ Question Regarding a ScreenCapture->Blur->ReturnBitmapHandle sequence...

Recommended Posts

tip

Hi to all,

     Recently I've been trying to create a routine to ScreenCapture a window, apply a blur effect to the captured image, return the blurred image bitmap handle and finally apply that bitmap to a PicCtrl using _SetBitmapToCtrl function. (I believe it is written by Zedna.) But I'm having hard time understanding how the GDI+ functions exactly work.

     I had found several blur effect scripts on the forum. One script has very gaussian-blur-like effect but it applies final bitmap directly to window(_WinAPI_GetDC etc.), the other one returns final bitmaps handle but the effect isn't as realistic imho. First one is written by Siao, can be found here: and the second one is written by UEZ, can be found here

     I've tried to integrate these two script and failed :graduated: Here is the last draft:

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#Include <ScreenCapture.au3>
 
_Main()
 
Func _WindowCapture_Blurred($i_HWND1)
 
Local $sRatio = 3, $iInterMode = 7, $iPixOffsetMode = 2, $iSmoothMode = 7
 
Local $tip_WindowClientInfo = _WinGetClientPos_Ex($i_HWND1,True)
 
_GDIPlus_Startup()
 
Local $hScreenCapture = _ScreenCapture_Capture("", $tip_WindowClientInfo[0],$tip_WindowClientInfo[1],$tip_WindowClientInfo[0]+$tip_WindowClientInfo[2],$tip_WindowClientInfo[1]+$tip_WindowClientInfo[3], False)
Local $hBitmapBig = _GDIPlus_BitmapCreateFromHBITMAP($hScreenCapture)
Local $hBitmapSmall = _GDIPlus_BitmapCloneArea($hBitmapBig, 0, 0, $tip_WindowClientInfo[2]/$sRatio, $tip_WindowClientInfo[3]/$sRatio)
Local $hGraphicSmall = _GDIPlus_ImageGetGraphicsContext($hBitmapSmall)
 
Local $hGraphicBig = _GDIPlus_GraphicsCreateFromHWND(_WinAPI_GetDesktopWindow())
 
;~  ;http://msdn2.microsoft.com/en-us/library/ms534141(VS.85).aspx
;~  ;InterpolationModeDefault = 0
;~  ;InterpolationModeLowQuality = 1
;~  ;InterpolationModeHighQuality = 2
;~  ;InterpolationModeBilinear = 3
;~  ;InterpolationModeBicubic = 4
;~  ;InterpolationModeNearestNeighbor = 5
;~  ;InterpolationModeHighQualityBilinear = 6
;~  ;InterpolationModeHighQualityBicubic = 7
    DllCall("gdiplus.dll", "int", "GdipSetInterpolationMode", "hwnd", $hGraphicBig, "int", $iInterMode)
    DllCall("gdiplus.dll", "int", "GdipSetInterpolationMode", "hwnd", $hGraphicSmall, "int", $iInterMode)
;~  ;http://msdn2.microsoft.com/en-us/library/ms534169(VS.85).aspx
;~  ;PixelOffsetModeDefault = 0 = PixelOffsetModeNone
;~  ;PixelOffsetModeHighSpeed = 1 = PixelOffsetModeNone
;~  ;PixelOffsetModeHighQuality = 2 = PixelOffsetModeHalf
;~  ;PixelOffsetModeNone = 3
;~  ;PixelOffsetModeHalf = 4
    DllCall("gdiplus.dll", "int", "GdipSetPixelOffsetMode", "hwnd", $hGraphicBig, "int", $iPixOffsetMode)
   DllCall("gdiplus.dll", "int", "GdipSetPixelOffsetMode", "hwnd", $hGraphicSmall, "int", $iPixOffsetMode)
;~  ;http://msdn2.microsoft.com/en-us/library/ms534173(VS.85).aspx
;~  ;SmoothingModeDefault = 0 = SmoothingModeNone
;~  ;SmoothingModeHighSpeed = 1 = SmoothingModeNone
;~  ;SmoothingModeHighQuality = 2 = SmoothingModeAntiAlias8x4
;~  ;SmoothingModeNone
;~  ;SmoothingModeAntiAlias8x4
;~  ;SmoothingModeAntiAlias = SmoothingModeAntiAlias8x4
;~  ;SmoothingModeAntiAlias8x8
    DllCall("gdiplus.dll", "int", "GdipSetSmoothingMode", "hwnd", $hGraphicBig, "int", $iSmoothMode)
    DllCall("gdiplus.dll", "int", "GdipSetSmoothingMode", "hwnd", $hGraphicSmall, "int", $iSmoothMode)
 
_GDIPlus_GraphicsDrawImageRect($hGraphicSmall, $hBitmapBig, 0, 0, $tip_WindowClientInfo[2], $tip_WindowClientInfo[3])
    _GDIPlus_GraphicsDrawImageRect($hGraphicBig, $hBitmapSmall, 0, 0, $tip_WindowClientInfo[2] / $sRatio, $tip_WindowClientInfo[3] / $sRatio)
 
$aRet = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmapBig)
 
_WinAPI_DeleteObject($hScreenCapture)
_GDIPlus_GraphicsDispose($hGraphicSmall)
_GDIPlus_GraphicsDispose($hGraphicBig)
_GDIPlus_BitmapDispose($hBitmapSmall)
_GDIPlus_BitmapDispose($hBitmapBig)
_GDIPlus_Shutdown()
    Return $aRet
EndFunc
 
Func _Main()
$Form1 = GUICreate("WindowCapture_Blurred Tryout", 640, 540, (@DesktopWidth-640)/2, (@DesktopHeight-560)/2)
    GUISetFont(10, 400, 0, "Segoe UI" ,$Form1,5)
    GUICtrlSetDefBkColor(-2,$Form1)
    GUISetBkColor(0x000000,$Form1)
$MenuItem1 = GUICtrlCreateMenu("&File")
$MenuItem2 = GUICtrlCreateMenuItem("Exit", $MenuItem1)
$Label1 = GUICtrlCreateLabel("     Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." _
     & " Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute" _
     & " irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat" _
     & " cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." & @CRLF & @CRLF & "    Suspendisse potenti. Fusce semper consequat suscipit. Quisque porttitor est eu felis pharetra lacinia. Donec mauris massa, aliquet " _
     & "vitae consectetur quis, laoreet in dolor. Cras fermentum vestibulum nulla, eget sollicitudin elit porttitor id. Nunc sapien nulla, blandit " _
     & "pellentesque sollicitudin et, dignissim non justo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. " _
     & "Vivamus congue ligula sed diam vehicula suscipit.", 30, 60, 580, 200)
GUICtrlSetColor(-1, 0xFFFFFF)
$Button1 = GUICtrlCreateButton("Try", 240, 300, 120, 25)
GUISetState(@SW_SHOW)
While 1
  $nMsg = GUIGetMsg()
  Switch $nMsg
   Case -3, $MenuItem2            ;   -3=$GUI_EVENT_CLOSE
    ExitLoop
   Case $Button1
    $a = _WinGetClientPos_Ex($Form1,True)
    $GUI2 = GUICreate("",$a[2],$a[3],$a[0]+$a[2],$a[1])
    $PicCtl = GUICtrlCreatePic("",0,0,$a[2],$a[3])
    $BlurredSS = _WindowCapture_Blurred($Form1)
     GUISetState()
    _SetBitmapToCtrl($PicCtl,$BlurredSS)
   EndSwitch
  WEnd
EndFunc
 
Func _SetBitmapToCtrl($CtrlId, $hBitmap)
    Local Const $STM_SETIMAGE = 0x0172
    Local Const $IMAGE_BITMAP = 0
    Local Const $SS_BITMAP = 0xE
    Local Const $GWL_STYLE = -16
    Local $hWnd = GUICtrlGetHandle($CtrlId)
    If $hWnd = 0 Then Return SetError(1, 0, 0)
        ; set SS_BITMAP style to control
    Local $oldStyle = DllCall("user32.dll", "long", "GetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE)
    If @error Then Return SetError(2, 0, 0)
    DllCall("user32.dll", "long", "SetWindowLong", "hwnd", $hWnd, "int", $GWL_STYLE, "long", BitOR($oldStyle[0], $SS_BITMAP))
    If @error Then Return SetError(3, 0, 0)
        Local $oldBmp = DllCall("user32.dll", "hwnd", "SendMessage", "hwnd", $hWnd, "int", $STM_SETIMAGE, "int", $IMAGE_BITMAP, "int", $hBitmap)
    If @error Then Return SetError(4, 0, 0)
    If $oldBmp[0] <> 0 Then _WinAPI_DeleteObject($oldBmp[0])
    Return 1
EndFunc
 
Func _WinGetClientPos_Ex($i_tip_Hwnd, $i_tip_ConsiderMenu = False)
If Not WinExists($i_tip_Hwnd) Or Not IsHWnd($i_tip_Hwnd) Then Return SetError(1,0,-1)
Local $i_tip_WinPos, $i_tip_ClientSize, $i_tip_BorderThickness, $i_tip_aRet
$i_tip_WinPos = WinGetPos($i_tip_Hwnd)
$i_tip_ClientSize = _WinGetClientSize_Ex($i_tip_Hwnd)
$i_tip_BorderThickness = ($i_tip_WinPos[2] - $i_tip_ClientSize[0])/2
Dim $i_tip_aRet[4] = [$i_tip_WinPos[0] + $i_tip_BorderThickness, $i_tip_WinPos[1] + ($i_tip_WinPos[3] - $i_tip_ClientSize[1]) - $i_tip_BorderThickness, $i_tip_ClientSize[0], $i_tip_ClientSize[1]]
If $i_tip_ConsiderMenu = True And $i_tip_ClientSize[2] > 0 Then
  $i_tip_aRet[1] -= $i_tip_ClientSize[2]
  $i_tip_aRet[3] = $i_tip_ClientSize[3]
EndIf
Return $i_tip_aRet
EndFunc ;==>_WinGetClientPos_Ex
 
Func _WinGetClientSize_Ex($i_tip_Hwnd)
If Not WinExists($i_tip_Hwnd) Or Not IsHWnd($i_tip_Hwnd) Then Return SetError(1,0,-1)
Local $i_tip_MenuExists, $i_tip_MenuExists, $i_tip_aRet
$i_tip_MenuExists = DllCall("User32.dll", "handle", "GetMenu", "hwnd", $i_tip_Hwnd)   ; We are checking if parent gui has a menu.
If @error Then
  $i_tip_MenuExists = 0
Else
  $i_tip_MenuExists = $i_tip_MenuExists[0]
  If $i_tip_MenuExists  > 0 Then
   $i_tip_MenuExists  = 20
  Else
   $i_tip_MenuExists  = 0
  EndIf
EndIf
$i_tip_aRet = WinGetClientSize($i_tip_Hwnd)
If IsArray($i_tip_aRet) = 0 Then
  Return SetError(2,0,-1)
Else
  ReDim $i_tip_aRet[4]
  $i_tip_aRet[2] = $i_tip_MenuExists
  $i_tip_aRet[3] = $i_tip_aRet[1] + $i_tip_aRet[2]
  Return $i_tip_aRet
EndIf
EndFunc ;==>_WinGetClientSize_Ex

     If you can point me to right direction I'd be very glad.

Sincerely

Tip

Edited by tip

[center]MsgBox_Tipped: Eye candy msgboxes/inputboxes/loginboxes. | CreateBlankBox: Semi-transparent layers with borders and rounded corners.[/center]

Share this post


Link to post
Share on other sites
UEZ

Try this one:

#include <ScreenCapture.au3>
#include <GUIConstantsEx.au3>
Opt("MustDeclareVars", 1)

Global Const $IMAGE_BITMAP = 0
Global Const $STM_SETIMAGE = 0x0172

_GDIPlus_Startup()
Global Const $hGUI = GUICreate("Blur Image and send to Pic Control", 285, 402)
Global Const $idPic = GUICtrlCreatePic("", 28, 40, 228, 322)
GUISetState()

Global Const $pid = Run("calc.exe")
ProcessWait($pid)


Global $hHBITMAP = _ScreenCapture_CaptureWnd("", WinGetHandle("[CLASS:CalcFrame]")) ;capture screen
Sleep(500)
ProcessClose($pid)

Global $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBITMAP) ;convert to GDI+ bitmap
_WinAPI_DeleteObject($hHBITMAP) ;delete image object because not needed anymore
Global Const $hBitmap_Blur = _Blur($hBitmap, 228, 322) ;blur GDI+ image
_GDIPlus_BitmapDispose($hBitmap) ;dispose bitmap because not needed anymore
$hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap_Blur) ;convert GDI+ bitmap to WinAPI bitmap (reuse of same variable)
_GDIPlus_BitmapDispose($hBitmap_Blur) ;dispose bitmap because not needed anymore
_WinAPI_DeleteObject(GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBITMAP)) ;send bitmap to picture control

Global $msg

Do
    $msg = GUIGetMsg()
Until $msg = $GUI_EVENT_CLOSE

_WinAPI_DeleteObject($hHBITMAP)
_GDIPlus_Shutdown()
GUIDelete($hGUI)

Exit

Func _Blur($hBitmap, $iW, $iH, $fScale = 0.666666, $qual = 6); by eukalyptus
    Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND(_WinAPI_GetDesktopWindow())
    Local $hBmpSmall = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics)
    Local $hGfxSmall = _GDIPlus_ImageGetGraphicsContext($hBmpSmall)
    DllCall($ghGDIPDll, "uint", "GdipSetPixelOffsetMode", "hwnd", $hGfxSmall, "int", 2)
    Local $hBmpBig = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics)
    Local $hGfxBig = _GDIPlus_ImageGetGraphicsContext($hBmpBig)
    DllCall($ghGDIPDll, "uint", "GdipSetPixelOffsetMode", "hwnd", $hGfxBig, "int", 2)
    DllCall($ghGDIPDll, "uint", "GdipScaleWorldTransform", "hwnd", $hGfxSmall, "float", $fScale, "float", $fScale, "int", 0)
    DllCall($ghGDIPDll, "uint", "GdipSetInterpolationMode", "hwnd", $hGfxSmall, "int", $qual)
    DllCall($ghGDIPDll, "uint", "GdipScaleWorldTransform", "hwnd", $hGfxBig, "float", 1 / $fScale, "float",  1 / $fScale, "int", 0)
    DllCall($ghGDIPDll, "uint", "GdipSetInterpolationMode", "hwnd", $hGfxBig, "int", $qual)
    _GDIPlus_GraphicsDrawImageRect($hGfxSmall, $hBitmap, 0, 0, $iW, $iH)
    _GDIPlus_GraphicsDrawImageRect($hGfxBig, $hBmpSmall, 0, 0, $iW, $iH)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_BitmapDispose($hBmpSmall)
    _GDIPlus_GraphicsDispose($hGfxSmall)
    _GDIPlus_GraphicsDispose($hGfxBig)
    Return $hBmpBig
EndFunc   ;==>_Blur

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
tip

UEZ, thanks for the quick reply. I had used your function but the blur effect is a bit distorted in comparison to Siao's. (I get that you didn't read the whole post :graduated:)

That's why I've tried to combine your code and his. Can you look at the code in the first post and help me to figure out what is wrong ;)


[center]MsgBox_Tipped: Eye candy msgboxes/inputboxes/loginboxes. | CreateBlankBox: Semi-transparent layers with borders and rounded corners.[/center]

Share this post


Link to post
Share on other sites
UEZ

Just play with the $fScale value :graduated:

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
tip

Thank you very much UEZ.

Finally I've figured out how to make blur effect more like gaussian blur. "GdipSetSmoothingMode" dllcall is what I needed. :D

Here is the code.

Func _GDIPlus_ImageBlur($hBitmap, $iStrenght = 3, $i_WinAPIBMP = False)
    If $iStrenght <= 1 Then $iStrenght = 1.01
    $iStrenght = 1/$iStrenght

    Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND(_WinAPI_GetDesktopWindow())
    $hBitmapWidth = _GDIPlus_ImageGetWidth($hBitmap)
    $hBitmapHeight = _GDIPlus_ImageGetHeight($hBitmap)
    Local $hBmpSmall = _GDIPlus_BitmapCreateFromGraphics($hBitmapWidth, $hBitmapHeight, $hGraphics)
    Local $hGfxSmall = _GDIPlus_ImageGetGraphicsContext($hBmpSmall)
    DllCall($ghGDIPDll, "uint", "GdipSetPixelOffsetMode", "hwnd", $hGfxSmall, "int", 2)
    Local $hBmpBig = _GDIPlus_BitmapCreateFromGraphics($hBitmapWidth, $hBitmapHeight, $hGraphics)
    Local $hGfxBig = _GDIPlus_ImageGetGraphicsContext($hBmpBig)
    DllCall($ghGDIPDll, "uint", "GdipSetSmoothingMode", "hwnd", $hGfxBig, "int", 7)
    DllCall($ghGDIPDll, "uint", "GdipSetSmoothingMode", "hwnd", $hGfxSmall, "int", 7)
    DllCall($ghGDIPDll, "uint", "GdipSetPixelOffsetMode", "hwnd", $hGfxBig, "int", 2)
    DllCall($ghGDIPDll, "uint", "GdipScaleWorldTransform", "hwnd", $hGfxSmall, "float", $iStrenght, "float", $iStrenght, "int", 0)
    DllCall($ghGDIPDll, "uint", "GdipSetInterpolationMode", "hwnd", $hGfxSmall, "int", 7)
    DllCall($ghGDIPDll, "uint", "GdipScaleWorldTransform", "hwnd", $hGfxBig, "float", 1 / $iStrenght, "float",  1 / $iStrenght, "int", 0)
    DllCall($ghGDIPDll, "uint", "GdipSetInterpolationMode", "hwnd", $hGfxBig, "int", 7)
    _GDIPlus_GraphicsDrawImageRect($hGfxSmall, $hBitmap, 0, 0, $hBitmapWidth, $hBitmapHeight)
    _GDIPlus_GraphicsDrawImageRect($hGfxBig, $hBmpSmall, 0, 0, $hBitmapWidth, $hBitmapHeight)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_BitmapDispose($hBmpSmall)
    _GDIPlus_GraphicsDispose($hGfxSmall)
    _GDIPlus_GraphicsDispose($hGfxBig)

    If $i_WinAPIBMP = True Then
        Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmpBig) ;convert GDI+ bitmap to WinAPI hbitmap
        _GDIPlus_BitmapDispose($hBmpBig)
        Return $hHBITMAP
    Else
        Return $hBmpBig
    EndIf
EndFunc   ;==>_GDIPlus_ImageBlur

Thanks again. Both UEZ and Siao...

Regards,

Tip


[center]MsgBox_Tipped: Eye candy msgboxes/inputboxes/loginboxes. | CreateBlankBox: Semi-transparent layers with borders and rounded corners.[/center]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×