Jump to content


Photo

[FUNC] LinearGradient - Create your own gradients


  • Please log in to reply
15 replies to this topic

#1 just me

just me
  • Members
  • 1175 posts

Posted 31 October 2011 - 10:13 AM

LinearGradient.png
This is a variation of an older script. You may use the function to fill a GUI Picture control with a linear gradient bitmap. At the best all you have to do is[*:33ewgsz5]Create a Picture control and get it's HWND (e.g. with the option hwndOutputVarHwnd)[*:33ewgsz5]Create an array of (at least two) integer RGB color values in left/right respectively top/bottom order[*:33ewgsz5]Call the function passing the control's HWND and the color array[*:33ewgsz5]Get a horizontal linear gradient as shown in the image aboveOptional parameters:[*:33ewgsz5]oPositions:
By default colors are evenly distributed from left to right / top to bottom. If you want to set the positions manually, pass an array containing the position of each color as a floating-point value starting with 0.0 (left/top) for the first color and ending with 1.0 (right/bottom) for the last color.

[*:33ewgsz5]D (Direction):
By default (0) the function creates a horizontal gradient. For other options look at the inline documentation, please.

[*:33ewgsz5]GC (Gamma Correction):
By default (0) gamma correction is turned off. You can pass 1 to turn it on.

[*:33ewgsz5]BW / BH:
By default the line gradient brush has the same size as the control's client area. You may play around with smaller values for the width (BW) and/or the height (BH) to get some "special effects".
LinearGradient.ahk:
; ======================================================================================================================
; Function:       LinearGradient
;                 Creates a linear gradient bitmap for a GUI Picture control. 
; AHK-Version:    1.1.05.00 U32
; OS-Versions:    Win Vista 32
; Author:         just me
; Parameter:      HWND        -  Control's HWND
;                 oColors     -  Array of integer RGB color values
;                                At least two colors must be passed, the start and the target color for the gradient
; (Optional)      oPositions  -  Array containing the relative positions of the color values as floating-point values 
;                                between 0.0 (start) and 1.0 (end) in ascending order
;                                Default: "" (or any non-object value)
;                                         Colors are divided automatically according to the number of colors.
;                 D           -  Direction:
;                                0 = horizontal
;                                1 = vertical
;                                2 = diagonal (upper-left -> lower-right)
;                                3 = diagonal (upper-right -> lower-left)
;                                Default: 0
;                 GC          -  Gamma Correction:
;                                0 = no
;                                1 = yes
;                                Default: 0
;                 BW          -  Brush width in pixel
;                                Default: 0 = control's width
;                 BH          -  Brush height in pixel
;                                Default: 0 = control's height
; ======================================================================================================================
LinearGradient(HWND, oColors, oPositions = "", D = 0, GC = 0, BW = 0, BH = 0) {
   ; -------------------------------------------------------------------------------------------------------------------
   ; Windows Constants
   Static SS_BITMAP    := 0xE
   Static SS_ICON      := 0x3
   Static STM_SETIMAGE := 0x172
   Static IMAGE_BITMAP := 0x0
   ; -------------------------------------------------------------------------------------------------------------------
   ; Check Parameters
   If !IsObject(oColors) || (oColors.MaxIndex() < 2) {
      ErrorLevel := "Invalid parameter oColors!"
      Return False
   }
   IC := oColors.MaxIndex()
   If IsObject(oPositions) {
      If (oPositions.MaxIndex() <> IC) {
         ErrorLevel := "Invalid parameter oPositions!"
         Return False
      }
   } Else {
      oPositions := [0.0]
      P := 1.0 / (IC - 1)
      Loop, % (IC - 2)
         oPositions.Insert(P * A_Index)
      oPositions.Insert(1.0)
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; Check HWND
   WinGetClass, Class, ahk_id %HWND%
   If (Class != "Static") {
      ErrorLevel := "Class " . Class . " is not supported!"
      Return False
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; Check the availability of GDIPlus
   If !DllCall("GetModuleHandle", "Str", "Gdiplus")
      hGDIP := DllCall("LoadLibrary", "Str", "Gdiplus")
   VarSetCapacity(SI, 16, 0)
   Numput(1, SI, "UInt")
   DllCall("Gdiplus.dll\GdiplusStartup", "PtrP", pToken, "Ptr", &SI, "Ptr", 0)
   If (!pToken) {
       ErrorLevel := "GDIPlus could not be started!`nCheck the availability of GDIPlus on your system, please!"
       Return False
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; Get client rectangle
   VarSetCapacity(RECT, 16, 0)
   DllCall("User32.dll\GetClientRect", "Ptr", HWND, "Ptr", &RECT)
   W := NumGet(RECT, 8, "Int")
   H := NumGet(RECT, 12, "Int")
   ; -------------------------------------------------------------------------------------------------------------------
   ; Set default parameter values
   If D Not In 0,1,2,3
      D := 0
   If GC Not In 0,1
      GC := 0
   If BW Not Between 1 And W
      BW := W
   If BH Not Between 1 And H
      BH := H
   ; -------------------------------------------------------------------------------------------------------------------
   ; Create a GDI+ bitmap
   DllCall("Gdiplus.dll\GdipCreateBitmapFromScan0", "Int", W, "Int", H, "Int", 0
         , "Int", 0x26200A, "Ptr", 0, "PtrP", pBitmap)
   ; -------------------------------------------------------------------------------------------------------------------
   ; Create a pointer to the corresponding graphic object
   DllCall("Gdiplus.dll\GdipGetImageGraphicsContext", "Ptr", pBitmap, "PtrP", pGraphics)
   ; -------------------------------------------------------------------------------------------------------------------
   ; Fill the bitmap with a linear gradient
   ; RECTF structure for line brush
   VarSetCapacity(RECTF, 16, 0)
   NumPut(BW, RECTF,  8, "Float")
   NumPut(BH, RECTF, 12, "Float")
   ; Create a linear gradient brush
   DllCall("Gdiplus.dll\GdipCreateLineBrushFromRect", "Ptr", &RECTF
         , "Int", 0, "Int", 0, "Int", D, "Int", 0, "PtrP", pBrush)
   ; Set gamma correction
   DllCall("Gdiplus.dll\GdipSetLineGammaCorrection", "Ptr", pBrush, "Int", GC)
   ; Set line preset blend colors ...
   VarSetCapacity(COLORS, IC * 4, 0)
   O := -4
   For I, V In oColors 
      NumPut(V | 0xFF000000, COLORS, O += 4, "UInt")
   ; ... and positions
   VarSetCapacity(POSITIONS, IC * 4, 0)
   O := -4
   For I, V In oPositions
      NumPut(V, POSITIONS, O += 4, "Float")
   DllCall("Gdiplus.dll\GdipSetLinePresetBlend", "Ptr", pBrush, "Ptr", &COLORS, "Ptr", &POSITIONS, "Int", IC)
   ; Fill the bitmap
   DllCall("Gdiplus.dll\GdipFillRectangle", "Ptr", pGraphics, "Ptr", pBrush
         , "Float", 0, "Float", 0, "Float", W, "Float", H)
   ; -------------------------------------------------------------------------------------------------------------------
   ; Create HBITMAP from bitmap
   DllCall("Gdiplus.dll\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "PtrP", hBitmap, "Int", 0X00FFFFFF)
   ; -------------------------------------------------------------------------------------------------------------------
   ; Free resources
   DllCall("Gdiplus.dll\GdipDisposeImage", "Ptr", pBitmap)
   DllCall("Gdiplus.dll\GdipDeleteBrush", "Ptr", pBrush)
   DllCall("Gdiplus.dll\GdipDeleteGraphics", "Ptr", pGraphics)
   ; Shutdown GDI+
   DllCall("Gdiplus.dll\GdiplusShutdown", "Ptr", pToken)
   If (hGDIP)
      DllCall("FreeLibrary", "Ptr", hGDIP)
   ; -------------------------------------------------------------------------------------------------------------------
   ; Set control styles
   Control, Style, -%SS_ICON%, , ahk_id %HWND%
   Control, Style, +%SS_BITMAP%, , ahk_id %HWND%
   ; Assign the bitmap
   SendMessage, STM_SETIMAGE, IMAGE_BITMAP, hBitmap, , ahk_id %HWND%
   ; Done!
   DllCall("Gdi32.dll\DeleteObject", "Ptr", hBitmap)
   Return True
}

LinearGradient_sample.ahk:
; LinearGradient_sample.ahk
#NoEnv
#Include *i Colors.ahk
Gui, Margin, 0, 0
Gui, Add, Pic, w480 h240 hwndHPIC
Colors := [0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF]
If !LinearGradient(HPIC, Colors)
   MsgBox, 0, Linear Gradient, Funtion failed:`n%ErrorLevel%
Gui, Font, s144, Tahoma
Gui, Add, Text, xp yp wp hp cNavy Center 0x200 vTX1 BackgroundTrans, AHK
Gui, Show, , Linear Gradient
Return
; ----------------------------------------------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
#Include LinearGradient.ahk

Enjoy! :wink:

Edit: Bugfix on LinearGradient.ahk!

#2 Guest Today

Guest Today
  • Guests

Posted 31 October 2011 - 07:22 PM

Using your sample code, I get

Unsupported use of "["
Specifically: [0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF]

I am using Autohotkey_L Ansi version on Windows 7.

#3 just me

just me
  • Members
  • 1175 posts

Posted 31 October 2011 - 08:34 PM

; AHK-Version: 1.1.05.00 U32



#4 Guests

  • Guests

Posted 04 November 2011 - 07:16 AM

An interesting function. What about to create a color picker control library with it? It would be useful for some various editor scripts.

#5 dylan904

dylan904
  • Members
  • 706 posts

Posted 14 August 2012 - 11:13 PM

I only get a salmon-colored GUI in the sample, is it supposed to be something different?

#6 just me

just me
  • Members
  • 1175 posts

Posted 17 August 2012 - 08:18 AM

Yes, of course. Which OS and AHK versions are you running?

#7 dylan904

dylan904
  • Members
  • 706 posts

Posted 21 August 2012 - 03:44 PM

win 7 x64 bit
ahk _L ANSI

#8 tomoe_uehara

tomoe_uehara
  • Members
  • 2077 posts

Posted 22 August 2012 - 04:18 AM

The image preview is broken :(

#9 just me

just me
  • Members
  • 1175 posts

Posted 22 August 2012 - 04:41 AM

@dylan904: No problems here with Win7x64 (Home Premium) and AHL 1.1.08.01 (ANSI).

@tomoe_uehara: You must be mistaken. :wink:

#10 cracksloth

cracksloth
  • Members
  • 15 posts

Posted 08 March 2013 - 08:18 PM

Linear gradient is great! I haven't had any luck with GDI+ (AHK_L Win8 64) but this works great.  I was wondering if you would consider throwing in a blur effect like:

 

Gdip_BlurBitmap(pBitmap, Blur)

 

I have two very similar colors in my gradient (for a more subtle effect) but because of this, I can see discrete lines in the gradient (bands of color).  I was thinking if I could blur the bitmap then those lines would disappear.  Does anyone have any advice?  Or perhaps justme could implement something similar into the function?  Thanks for the tremendous work!



#11 just me

just me
  • Members
  • 1175 posts

Posted 09 March 2013 - 06:10 AM

I can see discrete lines in the gradient (bands of color)

 

I cannot reproduce this. Would you post an example, please?



#12 cracksloth

cracksloth
  • Members
  • 15 posts

Posted 10 March 2013 - 03:11 AM

Just using your sample at size 600x600 and:

 

 

Colors := [0x525252, 0x101010]

I can see the lines of color rather than a smooth gradient.  I have uploaded an example here (make sure to "view original" to avoid compression artifacts).  Perhaps I am missing something? Are there deeper settings I need to adjust? 



#13 just me

just me
  • Members
  • 1175 posts

Posted 10 March 2013 - 07:40 AM

Well, I can see it now, though it's more smooth on Vista. I've tried  to use  Gdip_BlurBitmap(pBitmap, Blur) but didn't get satisfying results. If you want to try self:

   ; Fill the bitmap
   DllCall("Gdiplus.dll\GdipFillRectangle", "Ptr", pGraphics, "Ptr", pBrush
         , "Float", 0, "Float", 0, "Float", W, "Float", H)
   ; Added >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ; -------------------------------------------------------------------------------------------------------------------
   ; Blur
   BLUR := 50
   If (BLUR > 0) && (BLUR < 101) {
      DW := W // BLUR
      DH := H // BLUR
      DllCall("Gdiplus.dll\GdipCreateBitmapFromScan0", "Int", DW, "Int", DH, "Int", 0
            , "Int", 0x26200A, "Ptr", 0, "PtrP", pBitmapD)
      DllCall("Gdiplus.dll\GdipGetImageGraphicsContext", "Ptr", pBitmapD, "PtrP", pGraphicsD)
      ; DllCall("Gdiplus.dll\GdipGraphicsClear", "Ptr", pGraphicsD, "UInt", 0xFF000000)
      ; DllCall("Gdiplus.dll\GdipSetCompositingMode", "Ptr", pGraphicsD, "Int", 1) ; 0 | 1
      DllCall("Gdiplus.dll\GdipSetInterpolationMode", "Ptr", pGraphicsD, "Int", 7) ; 0 - 7
      DllCall("Gdiplus.dll\GdipDrawImageRectRect", "Ptr", pGraphicsD, "Ptr", pBitmap
            , "Float", 0, "Float", 0, "Float", DW, "Float", DH
            , "Float", 0, "Float", 0, "Float",  W, "Float",  H
            , "Int", 2, "Ptr", 0, "Ptr", 0, "Ptr", 0)
      ; DllCall("Gdiplus.dll\GdipGraphicsClear", "Ptr", pGraphics, "UInt", 0xFF000000)
      ; DllCall("Gdiplus.dll\GdipSetCompositingMode", "Ptr", pGraphics, "Int", 1) ; 0 | 1
      DllCall("Gdiplus.dll\GdipSetInterpolationMode", "Ptr", pGraphics, "Int", 7) ; 0 - 7
      DllCall("Gdiplus.dll\GdipDrawImageRectRect", "Ptr", pGraphics, "Ptr", pBitmapD
            , "Float", 0, "Float", 0, "Float",  W, "Float",  H
            , "Float", 0, "Float", 0, "Float", DW, "Float", DH
            , "Int", 2, "Ptr", 0, "Ptr", 0, "Ptr", 0)
      DllCall("Gdiplus.dll\GdipDeleteGraphics", "Ptr", pGraphicsD)
      DllCall("Gdiplus.dll\GdipDisposeImage", "Ptr", pBitmapD)
   }
   ; Added <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   ; -------------------------------------------------------------------------------------------------------------------
   ; Create HBITMAP from bitmap
   DllCall("Gdiplus.dll\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "PtrP", hBitmap, "UInt", 0X00FFFFFF)

 

 



#14 cracksloth

cracksloth
  • Members
  • 15 posts

Posted 10 March 2013 - 09:23 PM

I'm not sure entirely where to insert your code into the original script.  I have tried a few logical places but cannot detect any significant effect (if any).  Do you have any suggestions for alternative solutions?



#15 just me

just me
  • Members
  • 1175 posts

Posted 11 March 2013 - 05:59 AM

No, sorry. As I said, it looks smoother on my Vista PC. I've just tested on my Win8 laptop, and it is looking smoother also. Did you try to remove the transparentText control? Does it look different then?

 

BTW: The extra code should be inserted just before the lines

   ; -------------------------------------------------------------------------------------------------------------------
   ; Create HBITMAP from bitmap