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
#2
Posted 19 July 2012 - 09:30 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
#3
Posted 20 July 2012 - 03:43 AM
fantastic
#4
Posted 20 July 2012 - 06:22 AM
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.
#5
Posted 20 July 2012 - 09:51 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.
#6
Posted 20 July 2012 - 03:35 PM
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.




