GDI_GrayscaleBitmap( hBM ) { ; Converts GDI bitmap to 256 color GreyScale ; www.autohotkey.com/community/viewtopic.php?t=88996 By SKAN, Created : 19-Jul-2012 Static RGBQUAD256 If ! VarSetCapacity( RGBQUAD256 ) { VarSetCapacity( RGBQUAD256, 256*4, 0 ), Color := 0 Loop 255 Numput( Color := Color + 0x010101, RGBQUAD256, A_Index*4, "UInt" ) } VarSetCapacity( BM,24,0 ), DllCall( "GetObject", UInt,hBM, UInt,24, UInt,&BM ) W := NumGet( BM,4 ), H := NumGet( BM,8 ) hdcSrc := DllCall( "CreateCompatibleDC", UInt,0 ) hbmPrS := DllCall( "SelectObject", UInt,hdcSrc, UInt,hBM ) dBM := DllCall( "CopyImage", UInt , DllCall( "CreateBitmap", Int,2, Int,2, UInt,1, UInt,8, UInt,0 ) , UInt,0, Int,W, Int,H, UInt,0x2008, UInt ) hdcDst := DllCall( "CreateCompatibleDC", UInt,0 ) hbmPrD := DllCall( "SelectObject", UInt,hdcDst, UInt,dBM ) DllCall( "SetDIBColorTable", UInt,hdcDst, UInt,0, UInt,256, UInt,&RGBQUAD256 ) DllCall( "BitBlt", UInt,hdcDst, Int,0, Int,0, Int,W, Int,H , UInt,hdcSrc, Int,0, Int,0, UInt,0x00CC0020 ) DllCall( "SelectObject", UInt,hdcSrc, UInt,hbmPrS ) DllCall( "DeleteDC", UInt,hdcSrc ) DllCall( "SelectObject", UInt,hdcSrc, UInt,hbmPrD ) DllCall( "DeleteDC", UInt,hdcDst ) Return dBM }

GDI_GrayscaleBitmap() - Converts GDI bitmap to Greyscale
Started by
SKAN
, Jul 19 2012 09:27 PM
5 replies to this topic
#1
-
Posted 19 July 2012 - 09:27 PM

; I had always wanted to do this!!! - SKAN / 20 - Jul -2012 ; Simulation of Fade-to-Gray ( The effect when Shutdown prompt is activated in Win XP ) #SingleInstance, Force #NoTrayIcon hBM := GDI_CaptureScreen( 0, 0, A_ScreenWidth, A_ScreenHeight ) dBM := GDI_GrayscaleBitmap( hBM ), DllCall( "DeleteObject", UInt,hBM ) Gui -Caption +Owner +AlwaysOnTop +Lastfound Gui1 := WinExist() Gui, Margin, 0, 0 Gui, Add, Picture, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight% 0xE hwndcHwnd DllCall( "SendMessage", UInt,cHwnd, UInt,0x172, UInt,0, UInt,dBM ) OnExit, GuiEscape Gui, Show, x0 y0 w%A_ScreenWidth% h%A_ScreenHeight% Hide DllCall( "AnimateWindow", UInt,Gui1, Int,6000, UInt,0xa0000 ) Gui, 2:+Owner1 -Caption +Border +AlwaysOnTop Gui, 2:Color, CC0000 Gui, 2:Font, S14 Bold, Tahoma Gui, 2:Add, Text, cFAFAFA, <Esc> to exit Gui, 2:Show Return GDI_GrayscaleBitmap( hBM ) { ; Converts GDI bitmap to 256 color GreyScale ; www.autohotkey.com/community/viewtopic.php?t=88996 By SKAN, Created : 19-Jul-2012 Static RGBQUAD256 ; If ! VarSetCapacity( RGBQUAD256 ) { VarSetCapacity( RGBQUAD256, 256*4, 0 ), Color := 0 Loop 255 Numput( Color := Color + 0x010101, RGBQUAD256, A_Index*4, "UInt" ) } VarSetCapacity( BM,24,0 ), DllCall( "GetObject", UInt,hBM, UInt,24, UInt,&BM ) W := NumGet( BM,4 ), H := NumGet( BM,8 ) hdcSrc := DllCall( "CreateCompatibleDC", UInt,0 ) hbmPrS := DllCall( "SelectObject", UInt,hdcSrc, UInt,hBM ) dBM := DllCall( "CopyImage", UInt , DllCall( "CreateBitmap", Int,2, Int,2, UInt,1, UInt,8, UInt,0 ) , UInt,0, Int,W, Int,H, UInt,0x2008, UInt ) hdcDst := DllCall( "CreateCompatibleDC", UInt,0 ) hbmPrD := DllCall( "SelectObject", UInt,hdcDst, UInt,dBM ) DllCall( "SetDIBColorTable", UInt,hdcDst, UInt,0, UInt,256, UInt,&RGBQUAD256 ) DllCall( "BitBlt", UInt,hdcDst, Int,0, Int,0, Int,W, Int,H , UInt,hdcSrc, Int,0, Int,0, UInt,0x00CC0020 ) DllCall( "SelectObject", UInt,hdcSrc, UInt,hbmPrS ) DllCall( "DeleteDC", UInt,hdcSrc ) DllCall( "SelectObject", UInt,hdcSrc, UInt,hbmPrD ) DllCall( "DeleteDC", UInt,hdcDst ) Return dBM } GDI_CaptureScreen( X, Y, W, H, ByRef Checksum="" ) { ; By SKAN, Created : 10-Nov-2011 ; Screen Capture w/ Optional Checksum www.autohotkey.com/forum/viewtopic.php?t=35242 tDC := DllCall( "CreateCompatibleDC", UInt,0 ) hBM := DllCall( "CopyImage", UInt,DllCall( "CreateBitmap", Int,W, Int,H, UInt,1, UInt,24 , UInt,0 ), UInt,0, Int,0, Int,0, UInt,0x2008, UInt ) oBM := DllCall( "SelectObject", UInt,tDC, UInt,hBM ), hDC := DllCall( "GetDC", UInt,0 ) DllCall( "BitBlt" , UInt,tDC, UInt,0, UInt,0, Int,W, Int,H, UInt,hDC, UInt,X, UInt,Y, UInt,0x00CC0020 ) DllCall( "ReleaseDC", UInt,0, UInt,hDC ), DllCall( "SelectObject", UInt,tDC, UInt,oBM ) If ( Checksum <> "" ) VarSetCapacity( BM,24,0 ), DllCall( "GetObject", UInt,hBM, UInt,24, UInt,&BM ) , DllCall( "shlwapi\HashData", UInt,NumGet(BM,20), UInt,NumGet( BM,12 )*NumGet( BM,8 ) , Int64P,Checksum, UInt,7 ) Return hBM, DllCall( "DeleteDC", UInt,tDC ) } Esc:: 2GuiEscape: GuiEscape: OnExit ExitApp Return
#2
-
Posted 19 July 2012 - 09:30 PM

It is very slow on my computer, eventually due to dualscreen. If it wasn't for that, I would use this in my AHK arsenal. Nevertheless, very impressive! I'm sure there are good uses that do not include full-screen fading, and in those cases performance should be less of an issue.
#4
-
Posted 20 July 2012 - 06:22 AM

Very nice!Thanks for sharing
@sumon
Without using the animatewindow for a 1154,864 screen i get 0.24ms!!,maybe it only looks slow if you have the animatewindow feature on.
@sumon
Without using the animatewindow for a 1154,864 screen i get 0.24ms!!,maybe it only looks slow if you have the animatewindow feature on.
#5
-
Posted 20 July 2012 - 09:51 AM

winXP and ahk unicode
Thanks to everybody for the feedback 
I assure you that things can get better, but not faster.
Using Photoshop you can get better results with Optimized Octree Palette > Error Diffusion color reduction,
but this trick is limited to Windows Bitmap Palette > Get Nearest color method.
It should be the fastest method since BitBlt ( or StretchBlt ) does the 'closest color' matching automatically.
While experimenting to BitBlt from 24bit to 4bit, I learned it was not possible unless a DIB Color table is defined.
The experiment evolved as follows:
1) Borrow a color table method
2) Body-snatch method
3) Standalone method
GDI_GrayscaleBitmap() is the standalone method where I define a Color Table with 256 grey shades.
Starting from 000000 ( black ) I increment R,G,B component values by 1 until it reaches FFFFFF ( 255,255,255 )
Prior to it, I experimented with what I like to call as 'Body snatch' method where I simply opened an existing bitmap with 256 shades of gray in it, resized it to target size and BitBlt'd into it. Windows took care of the color reduction.
I guess things cannot get any simpler and faster. You may try it:
Color Tinting:
http://dl.dropbox.co...ample/256gs.bmp vs http://dl.dropbox.co...le/241green.bmp
In above code, search for
It is a different bitmap with 239 shades of dull green. Any BitBlt done into into it will give you a green tint instead of Greyscale.
If anyone is into OCR ( Optical Character Recognition ), just use a 1bit source bitmap and you will get an 1bpp screen capture.

It is very slow on my computer, eventually due to dualscreen. If it wasn't for that, I would use this in my AHK arsenal. Nevertheless, very impressive! I'm sure there are good uses that do not include full-screen fading, and in those cases performance should be less of an issue.
I assure you that things can get better, but not faster.
Using Photoshop you can get better results with Optimized Octree Palette > Error Diffusion color reduction,
but this trick is limited to Windows Bitmap Palette > Get Nearest color method.
It should be the fastest method since BitBlt ( or StretchBlt ) does the 'closest color' matching automatically.
While experimenting to BitBlt from 24bit to 4bit, I learned it was not possible unless a DIB Color table is defined.
The experiment evolved as follows:
1) Borrow a color table method
2) Body-snatch method
3) Standalone method
GDI_GrayscaleBitmap() is the standalone method where I define a Color Table with 256 grey shades.
Starting from 000000 ( black ) I increment R,G,B component values by 1 until it reaches FFFFFF ( 255,255,255 )
Prior to it, I experimented with what I like to call as 'Body snatch' method where I simply opened an existing bitmap with 256 shades of gray in it, resized it to target size and BitBlt'd into it. Windows took care of the color reduction.
I guess things cannot get any simpler and faster. You may try it:
#SingleInstance, Force SetWorkingDir %A_ScriptDir% SysGet, Mon, Monitor, 1 X := MonLeft, Y := MonTop, W := MonRight, H := MonBottom IfNotExist, % File := "256gs.bmp" URLDownloadToFile, http://dl.dropbox.com/u/6428211/Sample/%File%, %File% Qpx(1) ; Load ( with DIB Section ) and resize bitmap to target size hBM := DllCall( "LoadImage", UInt,0, Str,File, UInt,0, Int,W, Int,H, UInt,0x2010, UInt ) ; Select bitmap into Target DC tDC := DllCall( "CreateCompatibleDC", UInt,0 ) oBM := DllCall( "SelectObject", UInt,tDC, UInt,hBM ) ; Get Screen DC & Transfer Bits sDC := DllCall( "GetDC", UInt,0 ) DllCall( "BitBlt", UInt,tDC, UInt,X, UInt,Y, Int,W, Int,H , UInt,sDC, UInt,X, UInt,Y, UInt,0xC000CA ) ; Clean up DllCall( "ReleaseDC", UInt,0, UInt,sDC ) DllCall( "SelectObject", UInt,tDC, UInt,oBM ) DllCall( "DeleteDC", UInt,tDC ) tt := Qpx(0) Gui -Caption +Owner +AlwaysOnTop +Lastfound Gui1 := WinExist() Gui, Margin, 0, 0 Gui, Add, Picture, x0 y0 w%W% h%H% 0xE hwndcHwnd DllCall( "SendMessage", UInt,cHwnd, UInt,0x172, UInt,0, UInt,hBM ) Gui, Show, x0 y0 w%W% h%H% MsgBox, 4160, GreyScale, % "Screen resolution`t: " W "x" H "`nTime taken in secs`t: " tt ExitApp QPX( N=0 ) { ; Wrapper for QueryPerformanceCounter()by SKAN | CD: 06/Dec/2009 Static F,A,Q,P,X ; www.autohotkey.com/forum/viewtopic.php?t=52083 | LM: 10/Dec/2009 If ( N && !P ) Return DllCall("QueryPerformanceFrequency",Int64P,F) + (X:=A:=0) + DllCall("QueryPerformanceCounter",Int64P,P) DllCall("QueryPerformanceCounter",Int64P,Q), A:=A+Q-P, P:=Q, X:=X+1 Return ( N && X=N ) ? (X:=X-1)<<64 : ( N=0 && (R:=A/X/F) ) ? ( R + (A:=P:=X:=0) ) : 1 }
Color Tinting:
http://dl.dropbox.co...ample/256gs.bmp vs http://dl.dropbox.co...le/241green.bmp
In above code, search for
File := "256gs.bmp"
and replace 256gs.bmp with 241green.bmp.It is a different bitmap with 239 shades of dull green. Any BitBlt done into into it will give you a green tint instead of Greyscale.
If anyone is into OCR ( Optical Character Recognition ), just use a 1bit source bitmap and you will get an 1bpp screen capture.
#6
-
Posted 20 July 2012 - 03:35 PM
