Jump to content

Blurring the screen!?


Recommended Posts

ok first, here is my script :

#include <GUIConstants.au3>
HotKeySet("{F10}", "blur")


Func blur()
    
    $dc = DllCall("user32.dll", "int", "GetDC", "hwnd", "")
    $memory_dc = DllCall("gdi32.dll", "hwnd", "CreateCompatibleDC", "hwnd", $dc[0])
    $memory_bm = DllCall("gdi32.dll", "hwnd", "CreateCompatibleBitmap", "ptr", $dc[0], "int", @DesktopWidth, "int", @DesktopHeight)
    DllCall("gdi32.dll", "hwnd", "SelectObject", "hwnd", $memory_dc[0], "hwnd", $memory_bm[0])
    DllCall("gdi32.dll", "int", "BitBlt", "hwnd", $memory_dc[0], "int", 0, "int", 0, "int", @DesktopWidth, "int", @DesktopHeight, "hwnd", $dc[0], "int", 0, "int", 0, "int", 0xCC0020)
    Dim $x, $y, $cc, $t, $b, $l, $r
    for $x = 1 to @DesktopWidth-1
        for $y = 1 to @DesktopHeight-1
        #cs $cc = PixelGetColor($x, $y )
            $t = PixelGetColor($x, $y -1)
            $b = PixelGetColor($x, $y +1)
            $l = PixelGetColor($x-1, $y )
            $r = PixelGetColor($x+1, $y )
        #ce
        
        $cc = DllCall("gdi32.dll", "long", "GetPixel", "long", $memory_dc[0], "long", $x, "long", $y)

        $t = DllCall("gdi32.dll", "long", "GetPixel", "long", $memory_dc[0], "long", $x, "long", $y - 1)

        $b = DllCall("gdi32.dll", "long", "GetPixel", "long", $memory_dc[0], "long", $x, "long", $y + 1)

        $l = DllCall("gdi32.dll", "long", "GetPixel", "long", $memory_dc[0], "long", $x - 1, "long", $y)

        $r = DllCall("gdi32.dll", "long", "GetPixel", "long", $memory_dc[0], "long", $x + 1, "long", $y)


        
        $rv = Floor(BitShift(BitAND(0xFF0000, $cc[0]), 16) / 5 + BitShift(BitAND(0xFF0000, $l[0]), 16) / 5 + BitShift(BitAND(0xFF0000, $r[0]), 16) / 5 + BitShift(BitAND(0xFF0000, $t[0]), 16) / 5 + BitShift(BitAND(0xFF0000, $b[0]), 16) / 5)
        ;MsgBox(0,"",$r[0]1&"-"&$r[0]2&"-"&$r[0]3&"-"&$r[0]4&"-"&$r[0]5&"-"&$r[0]v)
        $gv = Floor((BitShift(BitAND(0x00ff00, $cc[0]), 8) / 5 + BitShift(BitAND(0x00ff00, $l[0]), 8) / 5 + BitShift(BitAND(0x00ff00, $r[0]), 8) / 5 + BitShift(BitAND(0x00ff00, $t[0]), 8) / 5 + BitShift(BitAND(0x00ff00, $b[0]), 8) / 5))
        $bv = Floor((BitAND(0xFF, $cc[0]) / 5 + BitAND(0xFF, $l[0]) / 5 + BitAND(0xFF, $r[0]) / 5 + BitAND(0xFF, $t[0]) / 5 + BitAND(0xFF, $b[0]) / 5))
        DllCall("gdi32.dll", "long", "SetPixel", "long", $dc[0], "long", $x, "long", $y, "long", "0x" & Hex($rv, 2) & Hex($gv, 2) & Hex($bv, 2))
        ;MsgBox(0,"","0x"&hex($rv,2)&hex($gv,2)&hex($bv,2))
        Next
    Next
EndFunc



While 1
    
    Sleep(1)
WEnd

aso you see, i capture the screen and get the pixels from the dc in the memory, and i also use bitshift for the color-modification. how can this take like 5 minutes to blur my screen? how can i do it in < 500ms ^^ ?

edit: ok it's like 10 million dllcalls, but how should that be possible without calling dll's in the loop ?

edit2: if there was just a way to work with pixeldata in hbitmaps directly :)

Edited by pixartist
Link to comment
Share on other sites

I neatend up your code but couldn't speed it up.

If you are not creating a GUI you don't need GUIConstants.au3

HotKeySet("{F10}", "blur")

While 1
    Sleep(100)
WEnd

Func blur()
    ConsoleWrite("Going to blur!" & @CRLF)
    $dc = DllCall("user32.dll", "int", "GetDC", "hwnd", "")
    $memory_dc = DllCall("gdi32.dll", "hwnd", "CreateCompatibleDC", "hwnd", $dc[0])
    $memory_bm = DllCall("gdi32.dll", "hwnd", "CreateCompatibleBitmap", "ptr", $dc[0], "int", @DesktopWidth, "int", @DesktopHeight)
    DllCall("gdi32.dll", "hwnd", "SelectObject", "hwnd", $memory_dc[0], "hwnd", $memory_bm[0])
    DllCall("gdi32.dll", "int", "BitBlt", "hwnd", $memory_dc[0], "int", 0, "int", 0, "int", @DesktopWidth, "int", @DesktopHeight, "hwnd", $dc[0], "int", 0, "int", 0, "int", 0xCC0020)
    Dim $x, $y, $cc, $t, $b, $l, $r
    For $x = 1 To @DesktopWidth - 1
        For $y = 1 To @DesktopHeight - 1
            $cc = DllCall("gdi32.dll", "long", "GetPixel", "long", $memory_dc[0], "long", $x, "long", $y)
            $t = DllCall("gdi32.dll", "long", "GetPixel", "long", $memory_dc[0], "long", $x, "long", $y - 1)
            $b = DllCall("gdi32.dll", "long", "GetPixel", "long", $memory_dc[0], "long", $x, "long", $y + 1)
            $l = DllCall("gdi32.dll", "long", "GetPixel", "long", $memory_dc[0], "long", $x - 1, "long", $y)
            $r = DllCall("gdi32.dll", "long", "GetPixel", "long", $memory_dc[0], "long", $x + 1, "long", $y)

            $rv = Floor(BitShift(BitAND(0xFF0000, $cc[0]), 16) / 5 + BitShift(BitAND(0xFF0000, $l[0]), 16) / 5 + BitShift(BitAND(0xFF0000, $r[0]), 16) / 5 + BitShift(BitAND(0xFF0000, $t[0]), 16) / 5 + BitShift(BitAND(0xFF0000, $b[0]), 16) / 5)
            $gv = Floor((BitShift(BitAND(0x00ff00, $cc[0]), 8) / 5 + BitShift(BitAND(0x00ff00, $l[0]), 8) / 5 + BitShift(BitAND(0x00ff00, $r[0]), 8) / 5 + BitShift(BitAND(0x00ff00, $t[0]), 8) / 5 + BitShift(BitAND(0x00ff00, $b[0]), 8) / 5))
            $bv = Floor((BitAND(0xFF, $cc[0]) / 5 + BitAND(0xFF, $l[0]) / 5 + BitAND(0xFF, $r[0]) / 5 + BitAND(0xFF, $t[0]) / 5 + BitAND(0xFF, $b[0]) / 5))
            DllCall("gdi32.dll", "long", "SetPixel", "long", $dc[0], "long", $x, "long", $y, "long", "0x" & Hex($rv, 2) & Hex($gv, 2) & Hex($bv, 2))
        Next
    Next
EndFunc  ;==>blur
Link to comment
Share on other sites

Would it be worth to get every other pixel, or every 3rd to speed it up? If you are bluring, then the pixel next to it isn't that important. Your goal is distortation, not sharp edges.

I tried this by adding Step 2 to the For loops, still slow and created more of a "lattice".

Edited by weaponx
Link to comment
Share on other sites

I would think you could use the integrated GDI functions in 3.2.10.0. Capture the screenshot to an object and then run the blur algorithm on it, this way you aren't getting each pixel individually.

EDIT: I found a link to a C++ example of this but my eyes went crossed.

http://www.codeproject.com/KB/GDI-plus/csh...aspx?print=true

Edited by weaponx
Link to comment
Share on other sites

Darn, if that worked I would have used it too! So this is why Windows Vista is so slow... it takes over a minute to fully "blur" my screen. Clever coding, though!

That isn't how Vista works. Vista uses Pixel Shaders wich is dedicated hardware for providing the effects you are trying to do. :)

Link to comment
Share on other sites

IMO no implementation of any gfx transform algo using only native AutoIt commands will be fast enough, especially if we are talking large resolutions. At least that's what my common sense tells me. Scripting languages are meant for other tasks.

So you're better off utilizing functions from some dlls.

Easy way is to use screen bitmap resizing with GDI+ which has various antialiasing settings.

You can play around with SetInterpolationMode, SetPixelOffsetMode etc...

For me HighQualityBilinear seems to provide the nicest blurs, especially when stretching alot.

#include <GUIConstants.au3>
#Include <ScreenCapture.au3>
#include <GDIPlus.au3>

$hGUI = GUICreate("Blurp", 200,120)
GUICtrlCreateLabel("InterpolationMode", 20, 20, 100, 20)
GUICtrlCreateLabel("Stretch ratio", 20, 50, 100, 20)
$cInputIM = GUICtrlCreateInput("6", 120, 15, 50, 20)
GUICtrlSetTip(-1, "Possible values" & @CRLF & "0 - 7")
$cInputSR = GUICtrlCreateInput("1.25", 120, 45, 50, 20)
GUICtrlSetTip(-1, "Possible values" & @CRLF & "1.0 - @DesktopHeight.0")
$cBtnBlur = GUICtrlCreateButton("Blur", 20, 80, 80, 20)
$cBtnClear = GUICtrlCreateButton("Clear", 100, 80, 80, 20)
GUISetState()

_GDIPlus_Startup()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _GDIPlus_Shutdown()
            Exit
        Case $cBtnBlur
            _ScreenBlur(GUICtrlRead($cInputSR), GUICtrlRead($cInputIM))
        Case $cBtnClear
            _ScreenClear()
    EndSwitch
WEnd

Func _ScreenClear()
    _WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE+$RDW_UPDATENOW+$RDW_ALLCHILDREN)
EndFunc
Func _ScreenBlur($nRatio, $iInterMode, $iSmoothMode=0, $iPixOffsetMode = 2)
    
    $hBMP = _ScreenCapture_Capture("", 0,0,-1,-1, False)
    $hImg = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)

    $hScreenDC = _WinAPI_GetDC(0)
    $hScreenGraph = _GDIPlus_GraphicsCreateFromHDC($hScreenDC)
    
    $hImg2 = _GDIPlus_BitmapCloneArea($hImg, 0, 0, @DesktopWidth/$nRatio, @DesktopHeight/$nRatio)
    $hMemGraph = _GDIPlus_ImageGetGraphicsContext($hImg2)
;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
    $a = DllCall("gdiplus.dll", "int", "GdipSetInterpolationMode", "hwnd", $hMemGraph, "int", $iInterMode)
    $a = DllCall("gdiplus.dll", "int", "GdipSetInterpolationMode", "hwnd", $hScreenGraph, "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
    $a = DllCall("gdiplus.dll", "int", "GdipSetPixelOffsetMode", "hwnd", $hMemGraph, "int", $iPixOffsetMode)
    $a = DllCall("gdiplus.dll", "int", "GdipSetPixelOffsetMode", "hwnd", $hScreenGraph, "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
    $a = DllCall("gdiplus.dll", "int", "GdipSetSmoothingMode", "hwnd", $hMemGraph, "int", $iSmoothMode)
    $a = DllCall("gdiplus.dll", "int", "GdipSetSmoothingMode", "hwnd", $hScreenGraph, "int", $iSmoothMode)

    _GDIPlus_GraphicsDrawImageRectRect($hMemGraph, $hImg, 0, 0, @DesktopWidth, @DesktopHeight, 0, 0, @DesktopWidth/$nRatio, @DesktopHeight/$nRatio)
    _GDIPlus_GraphicsDrawImageRectRect($hScreenGraph, $hImg2, 0, 0, @DesktopWidth/$nRatio, @DesktopHeight/$nRatio, 0, 0, @DesktopWidth, @DesktopHeight)
    
    _WinAPI_DeleteObject($hBMP)
    _GDIPlus_ImageDispose($hImg)
    _GDIPlus_ImageDispose($hImg2)
    _GDIPlus_GraphicsDispose($hMemGraph)
    _GDIPlus_GraphicsDispose($hScreenGraph)
    _WinAPI_ReleaseDC(0, $hScreenDC)

EndFunc

Edit: updated example - some tinkering with and documentation of modes.

Edited by Siao

"be smart, drink your wine"

Link to comment
Share on other sites

IMO no implementation of any gfx transform algo using only native AutoIt commands will be fast enough, especially if we are talking large resolutions. At least that's what my common sense tells me. Scripting languages are meant for other tasks.

So you're better off utilizing functions from some dlls.

Easy way is to use screen bitmap resizing with GDI+ which has various antialiasing settings.

You can play around with SetInterpolationMode, SetPixelOffsetMode etc...

For me HighQualityBilinear seems to provide the nicest blurs, especially when stretching alot.

#include <GUIConstants.au3>
#Include <ScreenCapture.au3>
#include <GDIPlus.au3>

$hGUI = GUICreate("Blurp", 200,120)
GUICtrlCreateLabel("InterpolationMode", 20, 20, 100, 20)
GUICtrlCreateLabel("Stretch ratio", 20, 50, 100, 20)
$cInputIM = GUICtrlCreateInput("6", 120, 15, 50, 20)
GUICtrlSetTip(-1, "Possible values" & @CRLF & "0 - 7")
$cInputSR = GUICtrlCreateInput("1.25", 120, 45, 50, 20)
GUICtrlSetTip(-1, "Possible values" & @CRLF & "1.0 - @DesktopHeight.0")
$cBtnBlur = GUICtrlCreateButton("Blur", 20, 80, 80, 20)
$cBtnClear = GUICtrlCreateButton("Clear", 100, 80, 80, 20)
GUISetState()

_GDIPlus_Startup()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _GDIPlus_Shutdown()
            Exit
        Case $cBtnBlur
            _ScreenBlur(GUICtrlRead($cInputSR), GUICtrlRead($cInputIM))
        Case $cBtnClear
            _ScreenClear()
    EndSwitch
WEnd

Func _ScreenClear()
    _WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE+$RDW_UPDATENOW+$RDW_ALLCHILDREN)
EndFunc
Func _ScreenBlur($nRatio, $iInterMode, $iSmoothMode=0, $iPixOffsetMode = 2)
    
    $hBMP = _ScreenCapture_Capture("", 0,0,-1,-1, False)
    $hImg = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)

    $hScreenDC = _WinAPI_GetDC(0)
    $hScreenGraph = _GDIPlus_GraphicsCreateFromHDC($hScreenDC)
    
    $hImg2 = _GDIPlus_BitmapCloneArea($hImg, 0, 0, @DesktopWidth/$nRatio, @DesktopHeight/$nRatio)
    $hMemGraph = _GDIPlus_ImageGetGraphicsContext($hImg2)
;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
    $a = DllCall("gdiplus.dll", "int", "GdipSetInterpolationMode", "hwnd", $hMemGraph, "int", $iInterMode)
    $a = DllCall("gdiplus.dll", "int", "GdipSetInterpolationMode", "hwnd", $hScreenGraph, "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
    $a = DllCall("gdiplus.dll", "int", "GdipSetPixelOffsetMode", "hwnd", $hMemGraph, "int", $iPixOffsetMode)
    $a = DllCall("gdiplus.dll", "int", "GdipSetPixelOffsetMode", "hwnd", $hScreenGraph, "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
    $a = DllCall("gdiplus.dll", "int", "GdipSetSmoothingMode", "hwnd", $hMemGraph, "int", $iSmoothMode)
    $a = DllCall("gdiplus.dll", "int", "GdipSetSmoothingMode", "hwnd", $hScreenGraph, "int", $iSmoothMode)

    _GDIPlus_GraphicsDrawImageRectRect($hMemGraph, $hImg, 0, 0, @DesktopWidth, @DesktopHeight, 0, 0, @DesktopWidth/$nRatio, @DesktopHeight/$nRatio)
    _GDIPlus_GraphicsDrawImageRectRect($hScreenGraph, $hImg2, 0, 0, @DesktopWidth/$nRatio, @DesktopHeight/$nRatio, 0, 0, @DesktopWidth, @DesktopHeight)
    
    _WinAPI_DeleteObject($hBMP)
    _GDIPlus_ImageDispose($hImg)
    _GDIPlus_ImageDispose($hImg2)
    _GDIPlus_GraphicsDispose($hMemGraph)
    _GDIPlus_GraphicsDispose($hScreenGraph)
    _WinAPI_ReleaseDC(0, $hScreenDC)

EndFunc

Edit: updated example - some tinkering with and documentation of modes.

wow thats actually pretty good! an fast!

thank you

Link to comment
Share on other sites

  • 4 weeks later...

I tried to run the example, but gdiplus.au3 gives errors.

A Messagebox appears with:

Fatal error: AVector: []: Out of bounds

After closing this message box I get the Blurp window, but when I click [blur] I get the same fatal error a few times

and the lower window in SCITE shows:

C:\Program Files\AutoIt3\Include\GDIPlus.au3 (415) : ==> Subscript used with non-Array variable.:

Return SetError($aResult[0], 0, $aResult[7])

Return SetError($aResult^ ERROR

I am using autoit v3.2.10.0 and WINNT4 (is this the reason?).

Link to comment
Share on other sites

I tried to run the example, but gdiplus.au3 gives errors.

A Messagebox appears with:

Fatal error: AVector: []: Out of bounds

After closing this message box I get the Blurp window, but when I click [blur] I get the same fatal error a few times

and the lower window in SCITE shows:

C:\Program Files\AutoIt3\Include\GDIPlus.au3 (415) : ==> Subscript used with non-Array variable.:

Return SetError($aResult[0], 0, $aResult[7])

Return SetError($aResult^ ERROR

I am using autoit v3.2.10.0 and WINNT4 (is this the reason?).

Windows NT does not come with GDI+ installed.
Link to comment
Share on other sites

  • 11 months later...

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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...