[GDIp] How to avoid colors getting blend when drawing brush with transparency?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
kauan014
Posts: 55
Joined: 18 Feb 2021, 20:03

[GDIp] How to avoid colors getting blend when drawing brush with transparency?

Post by kauan014 » 30 Jan 2022, 18:42

Code: Select all

pToken := Gdip_Startup()
OnMessage(0x0201, "WM_LBUTTONDOWN")


W      := 204
H      := 155
Color1 :=0xAA000000
Color2 :=0xAAFff0042

X1 := 4,  Y1 := 5,  W1 := 200, H1 := 150
X2 := 0, Y2 := 0, W2 := 200, H2 := 150
R  := 15



; Create the Bitmap.
DllCall("Gdiplus.dll\GdipCreateBitmapFromScan0", "Int", W, "Int", H, "Int", 0, "UInt", 0xE200B, "Ptr", 0, "PtrP", pBitmap)

; Get the pointer to its graphics.
DllCall("Gdiplus.dll\GdipGetImageGraphicsContext", "Ptr", pBitmap, "PtrP", PGRAPHICS)

; Quality settings
DllCall("Gdiplus.dll\GdipSetSmoothingMode", "Ptr", PGRAPHICS, "UInt", 4)
DllCall("Gdiplus.dll\GdipSetInterpolationMode", "Ptr", PGRAPHICS, "Int", 7)
DllCall("Gdiplus.dll\GdipSetCompositingQuality", "Ptr", PGRAPHICS, "UInt", 4)
DllCall("Gdiplus.dll\GdipSetRenderingOrigin", "Ptr", PGRAPHICS, "Int", 0, "Int", 0)
DllCall("Gdiplus.dll\GdipSetPixelOffsetMode", "Ptr", PGRAPHICS, "UInt", 4)

; Clear the background.
DllCall("Gdiplus.dll\GdipGraphicsClear", "Ptr", PGRAPHICS, "UInt", "") ;0xFFff0036)

; Create the path used to draw.
DllCall("Gdiplus.dll\GdipCreatePath", "UInt", 0, "PtrP", PATH)



; -----------------------
; First:
PathAddRoundedRect(Path, X1, Y1, W1+X1, H1+Y1, R)
DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", Color1, "PtrP", PBRUSH)
; Fill the path
DllCall("Gdiplus.dll\GdipFillPath", "Ptr", PGRAPHICS, "Ptr", PBRUSH, "Ptr", PATH)



; -----------------------
; Second:
DllCall("Gdiplus.dll\GdipResetPath", "Ptr", PATH)
PathAddRoundedRect(Path, X2, Y2, W2+X2, H2+Y2, R)
DllCall("Gdiplus.dll\GdipCreateSolidFill", "UInt", Color2, "PtrP", PBRUSH)
; Fill the path
DllCall("Gdiplus.dll\GdipFillPath", "Ptr", PGRAPHICS, "Ptr", PBRUSH, "Ptr", PATH)



Gui, L: +HwndGuiL +E0x80000 +OwnDialogs +Resize -Caption

hdc := CreateCompatibleDC()
obm := SelectObject(hdc, put_hBitmap(pBitmap))

UpdateLayeredWindow(GuiL, hdc, 0, 0, W, H)
Gui, L: Show, w%W% h%H%
Return


PathAddRoundedRect(Path, X1, Y1, X2, Y2, R) {      
   
   D := (R * 2), X2 -= D, Y2 -= D
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", Path, "Float", X1, "Float", Y1, "Float", D, "Float", D, "Float", 180, "Float", 90)
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", Path, "Float", X2, "Float", Y1, "Float", D, "Float", D, "Float", 270, "Float", 90)
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", Path, "Float", X2, "Float", Y2, "Float", D, "Float", D, "Float", 0, "Float", 90)
   DllCall("Gdiplus.dll\GdipAddPathArc", "Ptr", Path, "Float", X1, "Float", Y2, "Float", D, "Float", D, "Float", 90, "Float", 90)
   
   Return DllCall("Gdiplus.dll\GdipClosePathFigure", "Ptr", Path)

}

put_hBitmap(pBitmap, alpha := "") {
   ; Revert to built in functionality if a replacement color is declared.
   if (alpha != "") { ; This built-in version is about 25% slower.
      DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "ptr", pBitmap, "ptr*", hbm:=0, "uint", alpha)
      return hbm
   }

   ; Get Bitmap width and height.
   DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0)
   DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0)

   ; Convert the source pBitmap into a hBitmap manually.
   ; struct BITMAPINFOHEADER - https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader
   hdc := DllCall("CreateCompatibleDC", "ptr", 0, "ptr")
   VarSetCapacity(bi, 40, 0)              ; sizeof(bi) = 40
      NumPut(       40, bi,  0,   "uint") ; Size
      NumPut(    width, bi,  4,   "uint") ; Width
      NumPut(  -height, bi,  8,    "int") ; Height - Negative so (0, 0) is top-left.
      NumPut(        1, bi, 12, "ushort") ; Planes
      NumPut(       32, bi, 14, "ushort") ; BitCount / BitsPerPixel
   hbm := DllCall("CreateDIBSection", "ptr", hdc, "ptr", &bi, "uint", 0, "ptr*", pBits:=0, "ptr", 0, "uint", 0, "ptr")
   obm := DllCall("SelectObject", "ptr", hdc, "ptr", hbm, "ptr")

   ; Transfer data from source pBitmap to an hBitmap manually.
   VarSetCapacity(Rect, 16, 0)            ; sizeof(Rect) = 16
      NumPut(  width, Rect,  8,   "uint") ; Width
      NumPut( height, Rect, 12,   "uint") ; Height
   VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0)   ; sizeof(BitmapData) = 24, 32
      NumPut( 4 * width, BitmapData,  8,    "int") ; Stride
      NumPut(     pBits, BitmapData, 16,    "ptr") ; Scan0
   DllCall("gdiplus\GdipBitmapLockBits"
            ,    "ptr", pBitmap
            ,    "ptr", &Rect
            ,   "uint", 5            ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly
            ,    "int", 0xE200B      ; Format32bppPArgb
            ,    "ptr", &BitmapData) ; Contains the pointer (pBits) to the hbm.
   DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", pBitmap, "ptr", &BitmapData)

   ; Cleanup the hBitmap and device contexts.
   DllCall("SelectObject", "ptr", hdc, "ptr", obm)
   DllCall("DeleteDC",     "ptr", hdc)

   return hbm
}

Resulted:
w1.png
w1.png (2.25 KiB) Viewed 277 times
Trying to achieve this result:
w2.png
w2.png (1.8 KiB) Viewed 277 times
In the second picture the red is blended with the black from the second path (this is the picture resulted from the function above).

In the first picture it doesn't (this is what im trying to achieve).
explorer_2022-01-30_20-41-08.png
explorer_2022-01-30_20-41-08.png (5.4 KiB) Viewed 277 times
Is possible to achieve this result other than setting transparency in the entire picture and drawing the brushes without any transparency?

Return to “Ask for Help (v1)”