Jump to content

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

GDI_GrayscaleBitmap() - Converts GDI bitmap to Greyscale


  • Please log in to reply
5 replies to this topic
SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
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

}


kWo4Lk1.png

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
; 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



Alpha Bravo
  • Members
  • 1687 posts
  • Last active: Nov 07 2015 03:06 PM
  • Joined: 01 Sep 2011
fantastic

sumon
  • Moderators
  • 1317 posts
  • Last active: Dec 05 2016 10:14 PM
  • Joined: 18 May 2010
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.

noname
  • Members
  • 650 posts
  • Last active:
  • Joined: 12 Nov 2011
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.

winXP  and ahk unicode


SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Thanks to everybody for the feedback :)

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.