Jump to content


Photo

Crazy Scripting : Bitmap Gradients


  • Please log in to reply
6 replies to this topic

#1 SKAN

SKAN
  • Administrators
  • 9062 posts

Posted 01 March 2011 - 09:09 AM

GDI_CreateGradientBitmap()
GDI_CropBitmap()
GDI_cHDCtoBitmap()
GDI_SaveBitmap()

along with demo code


Posted Image[/list]
Gui, Add, DDL, w134 R5 hwndCBOX2 AltSubmit gUpdateGradient vGradientType
     , Vertical Linear|Horizontal Linear|Sunburst||Horizontal Bi-Linear|Vertical Bi-Linear
Gui, Add, Edit, x+5 w55 hp Center Uppercase Limit6 vColor1, ABCDEF
Gui, Add, Edit, x+5 w55 hp Center Uppercase Limit6 vColor2, 123456
Gui, Add, Picture, x10 y+5 w256 h256 0x120E hwndcHwnd
Gui, Show,, CreateGradientBitmap()
Gui, Add, Button, +Default gUpdateGradient

UpdateGradient:
 Gui, Submit, NoHide
 DllCall( "DeleteObject", UInt,hBMP )
 hBMP := GDI_CreateGradientBitmap( GradientType, Color1, Color2, 256, 256 )
 DllCall( "SendMessage", UInt,cHwnd, UInt,0x172, UInt,0, UInt,hBMP ) ; STM_SETIMAGE

Return                                                 ; // end of auto-execute section //

GDI_CreateGradientBitmap( G=3, C1="ABCDEF", C2="123456", W=256, H=256 ) {
 ; Thanks to HotkeyIt : www.autohotkey.com/forum/viewtopic.php?t=37376
 ; This post : www.autohotkey.com/forum/viewtopic.php?p=425387#425387
 D := ( G := G<1||G>5 ? 3:G ) < 3 ? 2 : 3,  SZ := D*D*4,  VarSetCapacity( B$,40+SZ,0 )
 ; Init BITMAPINFOHEADER ( 40 Bytes )
 NumPut(SZ,NumPut(0x180001,NumPut(D,NumPut(D,NumPut(40,B$))))+4), C1:="0x" C1, C2:="0x" C2
 ; Dynamic BITMAP Data
 _ := G=1 ? NumPut(C1,NumPut(C1,NumPut(C2,NumPut(C2,&B$+40)-1)+1)-1) : G=2 ? NumPut(C2
 ,NumPut(C1,NumPut(C2,NumPut(C1,&B$+40)-1)+1)-1) : G=3 ? NumPut(C2,NumPut(C2,NumPut(C2
 ,NumPut(C2,NumPut(C1,NumPut(C2,NumPut(C2,NumPut(C2,NumPut(C2,&B$+40)-1)-1)+2)-1)-1)+2)-1)
 -1):G=4 ? NumPut(C2,NumPut(C1,NumPut(C2,NumPut(C2,NumPut(C1,NumPut(C2,NumPut(C2,NumPut(C1
 ,NumPut(C2,&B$+40)-1)-1)+2)-1)-1)+2)-1)-1) :G=5 ? NumPut(C2,NumPut(C2,NumPut(C2,NumPut(C1
 ,NumPut(C1,NumPut(C1,NumPut(C2,NumPut(C2,NumPut(C2,&B$+40)-1)-1)+2)-1)-1)+2)-1)-1) : 0
 ; Obtain GDI Bitmap
 hBM := DllCall( "CreateDIBitmap", UInt, hDC := DllCall( "GetDC", UInt,cHwnd   ), UInt,&B$
      , Int,6, UInt,&B$+40, UInt,&B$, UInt,1 ), DllCall( "ReleaseDC", UInt,hDC )
 ; Obtain Resized GDI Bitmap / Obtain a copy with DIB section
 hBM := DllCall( "CopyImage", UInt,hBM, UInt,0, Int,W, Int,H, UInt,0x8, UInt )
 Return DllCall( "CopyImage", UInt,hBM, UInt,0, Int,0, Int,0, UInt,0x2000|0x8, UInt )
}

/*

The following five files were created in imaging software and used as reference in writing
CreateGradientBitmap().

Vertical Linear.bmp ( 2x2 24bpp, 70 Bytes )
BITMAPFILEHEADER: 424D460000000000000036000000
BITMAPINFOHEADER: 28000000020000000200000001001800000000001000000000000000000000000000000000000000
BITMAP Data     : 563412 563412 0000 EFCDAB EFCDAB 0000

Horizontal Linear.bmp ( 2x2 24bpp, 70 Bytes )
BITMAPFILEHEADER: 424D460000000000000036000000
BITMAPINFOHEADER: 28000000020000000200000001001800000000001000000000000000000000000000000000000000
BITMAP Data     : EFCDAB 563412 0000 EFCDAB 563412 0000

Sunburst.bmp ( 3x3 24bpp, 90 Bytes )
BITMAPFILEHEADER: 424D5A0000000000000036000000
BITMAPINFOHEADER: 28000000030000000300000001001800000000002400000000000000000000000000000000000000
BITMAP Data     : 563412 563412 563412 000000 563412 EFCDAB 563412 000000 563412 563412 563412 000000

Horizontal Bi-Linear.bmp ( 3x3 24bpp, 90 Bytes )
BITMAPFILEHEADER: 424D460000000000000036000000
BITMAPINFOHEADER: 28000000030000000300000001001800000000002400000000000000000000000000000000000000
BITMAP Data     : 563412 EFCDAB 563412 000000 563412 EFCDAB 563412 000000 563412 EFCDAB 563412 000000

Vertical Bi-Linear.bmp ( 3x3 24bpp, 90 Bytes )
BITMAPFILEHEADER: 424D460000000000000036000000
BITMAPINFOHEADER: 28000000030000000300000001001800000000002400000000000000000000000000000000000000
BITMAP Data     : 563412 563412 563412 000000 EFCDAB EFCDAB EFCDAB 000000 563412 563412 563412 000000

Note1 : BITMAPFILEHEADER is not required for CreateDIBitmap() and hence omitted from code.
Note2 : Reference for .bmp file format : www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html

How to Create a Diagonal Linear Gradient ?
:idea: :arrow: The simple way is to create a sunburst gradient and crop-out the desired quarter.

Posted Image
In the following demo, the above gradient is created and the right-bottom quarter is cropped-out
using an UDF: GDI_CropBitmap()

Edit: 15-June-2011
This example now captures bitmap from control HDC with GDI_cHDCtoBitmap()
and saves it as ahk.bmp through GDI_SaveBitmap()

Posted Image
tBMP := GDI_CreateGradientBitmap( 3, "DAFCDC", "1C8431", 256, 256 )
hBMP := GDI_CropBitmap( tBMP, 128, 128, 128, 128 )
DllCall( "DeleteObject", UInt,tBMP )

Gui +ToolWindow
Gui, Add, Picture, w128 h128 0x20E hwndcHwnd
DllCall( "SendMessage", UInt,cHwnd, UInt,0x172, UInt,0, UInt,hBMP ) ; STM_SETIMAGE
Gui, Font, S90 Bold, Arial Black
Gui, Add, Text, xp yp wp hp c005900 BackgroundTrans 0x201, H
Gui, Add, Text, xp-3 yp-3 wp hp cF8FCF8 BackgroundTrans 0x201, H
Gui, Show,, % " Diagonal Gradient"
WinWaitActive, % " Diagonal Gradient"
cBM := GDI_cHDCtoBitmap( cHwnd )
GDI_SaveBitmap( cBM, "ahk.bmp" )
DllCall( "DeleteObject", UInt,cBM )
Return


GDI_CreateGradientBitmap( G=3, C1="ABCDEF", C2="123456", W=256, H=256 ) {
 ; Thanks to HotkeyIt : www.autohotkey.com/forum/viewtopic.php?t=37376
 ; This post : www.autohotkey.com/forum/viewtopic.php?p=425387#425387
 D := ( G := G<1||G>5 ? 3:G ) < 3 ? 2 : 3,  SZ := D*D*4,  VarSetCapacity( B$,40+SZ,0 )
 ; Init BITMAPINFOHEADER ( 40 Bytes )
 NumPut(SZ,NumPut(0x180001,NumPut(D,NumPut(D,NumPut(40,B$))))+4), C1:="0x" C1, C2:="0x" C2
 ; Dynamic BITMAP Data
 _ := G=1 ? NumPut(C1,NumPut(C1,NumPut(C2,NumPut(C2,&B$+40)-1)+1)-1) : G=2 ? NumPut(C2
 ,NumPut(C1,NumPut(C2,NumPut(C1,&B$+40)-1)+1)-1) : G=3 ? NumPut(C2,NumPut(C2,NumPut(C2
 ,NumPut(C2,NumPut(C1,NumPut(C2,NumPut(C2,NumPut(C2,NumPut(C2,&B$+40)-1)-1)+2)-1)-1)+2)-1)
 -1):G=4 ? NumPut(C2,NumPut(C1,NumPut(C2,NumPut(C2,NumPut(C1,NumPut(C2,NumPut(C2,NumPut(C1
 ,NumPut(C2,&B$+40)-1)-1)+2)-1)-1)+2)-1)-1) :G=5 ? NumPut(C2,NumPut(C2,NumPut(C2,NumPut(C1
 ,NumPut(C1,NumPut(C1,NumPut(C2,NumPut(C2,NumPut(C2,&B$+40)-1)-1)+2)-1)-1)+2)-1)-1) : 0
 ; Obtain GDI Bitmap
 hBM := DllCall( "CreateDIBitmap", UInt, hDC := DllCall( "GetDC", UInt,cHwnd   ), UInt,&B$
      , Int,6, UInt,&B$+40, UInt,&B$, UInt,1 ), DllCall( "ReleaseDC", UInt,hDC )
 ; Obtain Resized GDI Bitmap / Obtain a copy with DIB section
 hBM := DllCall( "CopyImage", UInt,hBM, UInt,0, Int,W, Int,H, UInt,0x8, UInt )
 Return DllCall( "CopyImage", UInt,hBM, UInt,0, Int,0, Int,0, UInt,0x2000|0x8, UInt )
}

GDI_CropBitmap( hbm, x, y, w, h ) {                               ; By SKAN LM:28-Jun-2010
 ; This post : www.autohotkey.com/forum/viewtopic.php?p=425387#425387
 hdcSrc  := DllCall( "CreateCompatibleDC", UInt,0 )
 hdcDst  := DllCall( "CreateCompatibleDC", UInt,0 )
 VarSetCapacity( bm,24,0 ) ; BITMAP Structure
 DllCall( "GetObject", UInt,hbm, UInt,24, UInt,&bm )
 hbmOld  := DllCall( "SelectObject", UInt,hdcSrc, UInt,hbm )
 hbmNew  := DllCall( "CreateBitmap", Int,w, Int,h, UInt,NumGet( bm,16,"UShort" )
                    , UInt,NumGet( bm,18,"UShort" ), Int,0 )
 hbmOld2 := DllCall( "SelectObject", UInt,hdcDst, UInt,hbmNew )
 DllCall( "BitBlt", UInt,hdcDst, Int,0, Int,0, Int,w, Int,h
                  , UInt,hdcSrc, Int,x, Int,y, UInt,0x00CC0020 )
 DllCall( "SelectObject", UInt,hdcSrc, UInt,hbmOld )
 DllCall( "DeleteDC",  UInt,hdcSrc ),   DllCall( "DeleteDC",  UInt,hdcDst )
Return DllCall( "CopyImage", UInt,hbmNew, UInt,0, Int,0, Int,0, UInt,0x2008, UInt )
}

GDI_cHDCtoBitmap( hwnd )   {  ; By SKAN  www.autohotkey.com/forum/viewtopic.php?t=35242
 ControlGetPos,,,W,H,, ahk_id %hwnd%
 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", Int,hwnd )
 DllCall( "BitBlt",  UInt,tDC, Int64,0, Int,W, Int,H, UInt,hDC, Int64,0, UInt,0x00CC0020 )
 DllCall( "ReleaseDC", UInt,0, UInt,hDC ),   DllCall( "SelectObject", UInt,tDC, UInt,oBM )
 Return hBM, DllCall( "DeleteDC", UInt,tDC )
}

GDI_SaveBitmap( hBM, File ) {  ; By SKAN    www.autohotkey.com/forum/viewtopic.php?t=35242
 DllCall( "GetObject", Int,hBM, Int,VarSetCapacity($,84), UInt,NumPut(0,$,40,"Short")-42 )
 Numput( VarSetCapacity(BFH,14,0)+40, Numput((NumGet($,44)+54),Numput(0x4D42,BFH)-2)+4 )
 If ( hF := DllCall( "CreateFile", Str,File,UInt,2**30,UInt,2,Int,0,UInt,2,Int64,0 ) ) > 0
   DllCall( "WriteFile", UInt,hF, UInt,&BFH,  UInt,14, IntP,0,Int,0 ) ; BITMAPFILEHEADER
 , DllCall( "WriteFile", UInt,hF, UInt,&$+24, UInt,40, IntP,0,Int,0 ) ; BITMAPINFOHEADER
 , DllCall( "WriteFile", UInt,hF, UInt,NumGet($,20), UInt,NumGet($,44), UIntP,BW, Int,0 )
 , DllCall( "CloseHandle", UInt,hF )
Return BW ? 54+BW : 0
}



#2 sumon

sumon
  • Moderators
  • 1307 posts

Posted 02 March 2011 - 02:53 AM

Woaw, that is actually pretty sweet. Just gotta find an usage for it, and I'll gladly put it to use.

I tried using ColorPicker (a selfmodified version) to pick colors for the exercise, and felt pretty cool to do that kind of stuff without photo editing software.

#3 MasterFocus

MasterFocus
  • Moderators
  • 4126 posts

Posted 02 March 2011 - 03:23 AM

Another great piece of code by SKAN! Thanks!

#4 SoggyDog

SoggyDog
  • Members
  • 803 posts

Posted 02 March 2011 - 03:02 PM

Another great piece of code by SKAN! Thanks!

+1

#5 Learning one

Learning one
  • Members
  • 1294 posts

Posted 02 March 2011 - 07:23 PM

Very nice SKAN, I like it! Thanks! :)

#6 Wicked - Guest

Wicked - Guest
  • Guests

Posted 03 March 2011 - 11:55 AM

Believe it or not, after using AHK for years I never knew of the Limit property for an edit control.

Thanks, once again for an excellent piece of code!

#7 GuiUser

GuiUser
  • Guests

Posted 10 April 2011 - 07:31 PM

Hey SKAN,

many thanks for this, really useful, and nicely programmed function, helps to create nice looking gui's!

But I've found a terrible bug: it doesn't work correctly when changing the background color of the gui, and that color (or a similiar one) is used in the gradient. :cry:

Take a look at these pictures to see what I'm talking about:

Posted Image Posted Image

The only change I made to your example are these two extra lines:

Gui, Color, 000000, 000000
Gui, Font, cFFFFFF

Any ideas / fixes?