[GDI]How to create a bitmap with opacity? Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [GDI]How to create a bitmap with opacity?

Post by SKAN » 14 Jun 2021, 00:37

lexikos wrote:
13 Jun 2021, 22:22
SKAN wrote:
13 Jun 2021, 10:35
Please clarify whether LoadPicture() returned alpha bitmap is in ARGB or PARGB pixel format.
I don't even know what you're talking about.

It's in whatever format GdipCreateHBITMAPFromBitmap creates it in.
Okay :thumbup:
Behaviour of GdipCreateHBITMAPFromBitmap() has changed over windows versions.
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: [GDI]How to create a bitmap with opacity?

Post by teadrinker » 14 Jun 2021, 09:35

This script says that the format is GUID_WICPixelFormat32bppBGRA, which matches to Format32bppArgb.

Code: Select all

If !FileExist("T1.png")
   UrlDownloadToFile, https://www.autohotkey.com/boards/download/file.php?id=13666, T1.png

hBitmap := LoadPicture("T1.png", "GDI+")

FormatGUID := GetPixelFormat(hBitmap)
DllCall("DeleteObject", "Ptr", hBitmap)

; https://docs.microsoft.com/en-us/windows/win32/wic/-wic-codec-native-pixel-formats
MsgBox, % FormatGUID ; GUID_WICPixelFormat32bppBGRA := "{6FDDC324-4E03-4BFE-B185-3D77768DC90F}"

GetPixelFormat(hBitmap) {
   static CLSID_WICImagingFactory := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}"
         , IID_IWICImagingFactory := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}"
   pFactory := ComObjCreate(CLSID_WICImagingFactory, IID_IWICImagingFactory)
   ; IWICImagingFactory::CreateBitmapFromHBITMAP
   DllCall(NumGet(NumGet(pFactory + 0) + A_PtrSize*21), "Ptr", pFactory, "Ptr", hBitmap, "Ptr", 0, "Int", 0, "PtrP", pIWICBitmap)
   ; IWICBitmap::GetPixelFormat
   VarSetCapacity(GUID, 16, 0)
   DllCall(NumGet(NumGet(pIWICBitmap + 0) + A_PtrSize*4), "Ptr", pIWICBitmap, "Ptr", &GUID)
   ObjRelease(pIWICBitmap), ObjRelease(pFactory)
   Return StringFromGUID(GUID)
}

StringFromGUID(ByRef VarOrAddress) {
   pGuid := IsByRef(VarOrAddress) ? &VarOrAddress : VarOrAddress
   VarSetCapacity(sGuid, 78) ; (38 + 1) * 2
   if !DllCall("ole32\StringFromGUID2", "Ptr", pGuid, "Ptr", &sGuid, "Int", 39)
      throw Exception("Invalid GUID", -1, Format("<at {1:p}>", pGuid))
   return StrGet(&sGuid, "UTF-16")
}
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [GDI]How to create a bitmap with opacity?

Post by SKAN » 14 Jun 2021, 10:29

@teadrinker
teadrinker wrote:
14 Jun 2021, 09:35
This script says that the format is GUID_WICPixelFormat32bppBGRA, which matches to Format32bppArgb.
Thanks.

I actually re-used your code to test.
LoadPicture() definitely returns PARGB if source has alpha transparent pixels.
Ref: https://www.cgdirector.com/premultiplied-alpha-vs-straight-alpha/

Code: Select all

#NoEnv
#Warn
#SingleInstance, Force
SetWorkingDir, %A_ScriptDir%

If ! FileExist("T3.png")
     UrlDownloadToFile, https://www.autohotkey.com/boards/download/file.php?id=13723, T3.png

If ! FileExist("T4.png")
     UrlDownloadToFile, https://www.autohotkey.com/boards/download/file.php?id=13724, T4.png


hBm3 := LoadPicture("T3.png", "GDI+")
hBm4 := LoadPicture("T4.png", "GDI+")

VarSetCapacity(BITMAP, byteCount := 4*4 + A_PtrSize*2, 0)
DllCall("GetObject", "Ptr", hBm3, "Int", byteCount, "Ptr", &BITMAP)
pBits := NumGet(BITMAP, 4*4 + A_PtrSize)
MsgBox % Format("0xARGB =`t0x{:08X}", NumGet(pBits+0, "UInt"))


VarSetCapacity(BITMAP, byteCount := 4*4 + A_PtrSize*2, 0)
DllCall("GetObject", "Ptr", hBm4, "Int", byteCount, "Ptr", &BITMAP)
pBits := NumGet(BITMAP, 4*4 + A_PtrSize)
MsgBox % Format("0xARGB =`t0x{:08X}", NumGet(pBits+0, "UInt"))
 
If you have Windows 7, can you please test the script posted here:
https://www.autohotkey.com/boards/viewtopic.php?p=404930#p404930
LoadPicture() returns 32bpp alpha bitmap from a 1bpp monochrome bitmap.
I want to know the result/behaviour if screen bit depth is reduced to 24bpp or 16bpp.
Can't reduce screen bit-depth Windows 8 onwards and hence I'm asking. I have only 8.1 & 10.
Attachments
T4.png
T4.png (249 Bytes) Viewed 849 times
T3.png
T3.png (248 Bytes) Viewed 849 times
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [GDI]How to create a bitmap with opacity?

Post by SKAN » 14 Jun 2021, 10:58

@teadrinker

The following is for you to confirm that my T4.png is in ARGB format. (PNG supports only RGB/ARGB, I suppose)

Code: Select all

#NoEnv
#Warn
#SingleInstance, Force
SetWorkingDir, %A_ScriptDir%

Filename := "T4.png"
If ! FileExist(Filename)
     UrlDownloadToFile, https://www.autohotkey.com/boards/download/file.php?id=13724, %Filename%

VarSetCapacity(GdiplusStartupInput, 24, 0)
NumPut(1, GdiplusStartupInput, "Int")

hGdiPlus := DllCall("kernel32.dll\LoadLibrary", "Str","GdiPlus.dll", "Ptr")
DllCall("gdiplus.dll\GdiplusStartup", "PtrP",pToken:=0, "Ptr",&GdiplusStartupInput, "Int",0)
DllCall("gdiplus.dll\GdipCreateBitmapFromFile", "WStr",Filename, "PtrP",pBitmap:=0)
DllCall("gdiplus.dll\GdipGetImagePixelFormat", "Ptr",pBitmap, "PtrP",PixelFormat:=0)

MsgBox % PixelFormat ; PixelFormat32bppARGB = 2498570

DllCall("gdiplus.dll\GdiplusShutdown", "Ptr",pToken)
DllCall("kernel32.dll\FreeLibrary", "Ptr",hGdiPlus)
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: [GDI]How to create a bitmap with opacity?

Post by teadrinker » 14 Jun 2021, 11:28

SKAN wrote: If you have Windows 7, can you please test the script posted here:
https://www.autohotkey.com/boards/viewtopic.php?p=404930#p404930
On Windows 7 this code returns 1. The same if I reduce screen bit-depth to 16 bpp. Didn't find a way to reduce to 24 bits per pixel.
SKAN wrote: The following is for you to confirm that my T4.png is in ARGB format. (PNG supports only RGB/ARGB, I suppose)
On Windows 7 it returns 2498570.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [GDI]How to create a bitmap with opacity?

Post by SKAN » 14 Jun 2021, 13:48

@teadrinker

Thank you very much for the testing. 🙏.
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

Re: [GDI]How to create a bitmap with opacity?

Post by pv007 » 16 Jun 2021, 01:36

@SKAN

Code: Select all

hBitmap := LoadPicture("pic.png")
Gui, Add, Picture, ,% "HBITMAP:" . hBitmap

hBitmap2 := LoadPicture("pic.png")
SetTransparency(hBitmap2, 90)
Gui, Add, Picture, ,% "HBITMAP:" . hBitmap2

Gui, Show
When the picture has an empty area and I set transparency to it, it gets a different color when added to the GUI, any idea why?
pic.png
pic.png (273 Bytes) Viewed 789 times
image.png
image.png (2.18 KiB) Viewed 787 times
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [GDI]How to create a bitmap with opacity?

Post by SKAN » 16 Jun 2021, 02:49

pv007 wrote:
16 Jun 2021, 01:36
When the picture has an empty area and I set transparency to it, it gets a different color when added to the GUI, any idea why?
That is what I and @teadrinker were discussing about.
@teadrinker's SetTransparency() would work fine if LoadPicture() returned ARGB bitmap, but seemingly, a PARGB bitmap is being returned.
I suggest you to try my Imagen()
 

Code: Select all

#NoEnv
#Warn
#SingleInstance, Force
SetWorkingDir, %A_ScriptDir%

hBitmap := LoadPicture("pic.png")
Gui, Add, Picture, ,% "HBITMAP:" . hBitmap

hBitmap2 := LoadPicture("pic.png")
Imagen("HBITMAP:" . hBitmap2, "?Normal:90 BackgroundTrans", hBitmap2)
Gui, Add, Picture, ,% "HBITMAP:" . hBitmap2

Gui, Show
 
image.png
image.png (2 KiB) Viewed 781 times
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

Re: [GDI]How to create a bitmap with opacity?

Post by pv007 » 16 Jun 2021, 04:50

Code: Select all

hBitmap := LoadPicture("pic.png")
Gui, Add, Picture, ,% "HBITMAP:" . hBitmap

hBitmap2 := LoadPicture("pic.png")
SetTransparency(hBitmap2, 90)
Gui, Add, Picture, ,% "HBITMAP:" . hBitmap2

hBitmap3 := LoadPicture("pic.png")
Imagen("HBITMAP:" . hBitmap3, "?Normal:90 BackgroundTrans", hBitmap3)
Gui, Add, Picture, ,% "HBITMAP:" . hBitmap3

Gui, Show
Return
image.png
image.png (2.34 KiB) Viewed 772 times
@SKAN the colors looks different from SetTransparency function and Imagen

Oh, I figured why, it's because of the option BackgroundTrans.

I'm loading a picture as the background of some GUI controls, using BitBlt
But when I load the hBitmap from Imagen() into the dc, the transparent area still continues white, any idea why?

Code: Select all


SELDC := DllCall("Gdi32.dll\CreateCompatibleDC", "Ptr", , "UPtr")

hBitmap := LoadPicture("pic.png")
Imagen("HBITMAP:" . hBitmap, "?Normal:90 ", hBitmap)

DllCall("Gdi32.dll\SelectObject", "Ptr", SELDC, "Ptr", hBitmap)

VarSetCapacity(PAINTSTRUCT, A_PtrSize + (4 * 7) + 32 + (A_PtrSize - 4), 0)

LBDC := DllCall("USer32.dll\BeginPaint", "Ptr", hWnd, "Ptr", &PAINTSTRUCT, "UPtr")

DllCall("Gdi32.dll\SetBkMode", "Ptr", LBDC, "Int", 1) ; TRANSPARENT

VarSetCapacity(RECT, 16, 0)
DllCall("GetClientRect", "Ptr", hWnd, "Ptr", &RECT)

L := NumGet(RECT, 0, "Int") 
T := NumGet(RECT, 4, "Int")
W := NumGet(RECT, 8, "Int") - L 
H := NumGet(RECT, 12, "Int") - T

;FileAppend, W: %W% H: %H% T: %T% L: %L%`n,*

SRCCOPY := 0x00CC0020
DllCall("Gdi32.dll\BitBlt", "Ptr", LBDC, "Int", L, "Int", T, "Int", W, "Int", H, "Ptr", SELDC, "Int", 0, "Int", 0, "UInt", SRCCOPY)
image.png
image.png (1.21 KiB) Viewed 766 times
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [GDI]How to create a bitmap with opacity?

Post by SKAN » 16 Jun 2021, 05:21

pv007 wrote:
16 Jun 2021, 04:50

Code: Select all

DllCall("Gdi32.dll\BitBlt", "Ptr", LBDC, "Int", L, "Int", T, "Int", W, "Int", H, "Ptr", SELDC, "Int", 0, "Int", 0, "UInt", SRCCOPY)
None of Gdi32 functions including BitBlt() can handle alpha transparency.
The only exceptional function is GdiAlphablend() which Imagen() uses to render fade-in animation in a picture control.
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

Re: [GDI]How to create a bitmap with opacity?

Post by pv007 » 16 Jun 2021, 05:50

@SKAN

Code: Select all

Gui, Font, s10
Gui, Color, 854506

Transparency := 90

TextColor := "White"

HBITMAP := LoadPicture("pic.png")
Imagen("HBITMAP:" . HBITMAP, "?Normal:90 ", HBITMAP)
Gui, Add, Text, w156 h24 c%TextColor%, Imagen 
Gui, Add, Text, xp yp wp hp hwndhText ,

T := New paintDC(hText, HBITMAP, Transparency)
T.SetRedraw(True)

; ------------------------------------------------------------

HBITMAP2 := LoadPicture("pic.png")
Imagen("HBITMAP:" . HBITMAP2, "?Normal:90 BackGroundTrans", HBITMAP2)
Gui, Add, Text, xm w156 h24 c%TextColor%, Imagen +BGTrans
Gui, Add, Text, xp yp wp hp hwndhText2  +BackgroundTrans, 

T2 := New paintDC(hText2, HBITMAP2, Transparency)
T2.SetRedraw(True)

; ------------------------------------------------------------

HBITMAP3 := LoadPicture("pic.png")
SetTransparency(HBITMAP3, 90)
Gui, Add, Text, xm w156 h24 c%TextColor%, SetTransparency
Gui, Add, Text, xp yp wp hp hwndhText3 ,

T3 := New paintDC(hText3, HBITMAP3, Transparency)
T3.SetRedraw(True)




; ------------------------------------------------------------
; IMAGEN + BackgroundTrans

Imagen_hBitmap := LoadPicture("pic.png")
Imagen("HBITMAP:" . Imagen_hBitmap, "?Normal:90 BackGroundTrans", Imagen_hBitmap)
Gui, Add, Text, xm y+40 w156 h24 c%TextColor%, Imagen_hBitmap
Gui, Add, Picture, xp yp  +BackGroundTrans,% "HBITMAP:" . Imagen_Hbitmap

; --------------------------------------------

; SET TRANSPARENCY
SetTrans_hBitmap := LoadPicture("pic.png")
SetTransparency(SetTrans_hBitmap, 90)
Gui, Add, Text, x+20 yp w156 h24 c%TextColor%, SetTrans_hBitmap
Gui, Add, Picture, xp yp  +BackGroundTrans,% "HBITMAP:" . SetTrans_hBitmap


Gui, Show, w500 h300


return


Class paintDC {

   __New(hWnd, hBitmap, Transparency)  {
      This.HLB := hWnd
      This.hBitmap := hBitmap
      This.Transparency := Transparency
      This.HasBackground := False
      This.Drawing := True
      SCCB := RegisterCallback("paintDC.SubClassCallback")
      DllCall("Comctl32.dll\SetWindowSubclass", "Ptr", hWnd, "Ptr", SCCB, "Ptr", hWnd, "Ptr", &This)
   }

   SubClassCallback(uMsg, wParam, lParam, IdSubclass, RefData) {
      Critical 100
      hWnd := This ; first parameter 'hWnd' is passed as 'This'
      Return Object(RefData).SubClassProc(hWnd, uMsg, wParam, lParam)
   }
      
   SubClassProc(hWnd, uMsg, wParam, lParam) {
   
      Static WM := { ERASEBKGND: 0x0014, PAINT: 0x000F }

      If (uMsg = WM.ERASEBKGND) {         
         If (!This.HasBackground) {            
            ;FileAppend, Erase! `n,*
            SELDC := DllCall("Gdi32.dll\CreateCompatibleDC", "Ptr", , "UPtr")

            pBitmap := Gdip_CreateBitmapFromHBITMAP(This.hBitmap)
            Gdip_GetImageDimension(pBitmap, W, H)
            
            This.Width := W
            This.Height := H
            Gdip_DisposeImage(pBitmap)

            DllCall("Gdi32.dll\SelectObject", "Ptr", SELDC, "Ptr", This.hBitmap)
            This.SELDC := SELDC
            This.HasBackground := True
         }
      }

      If (uMsg = WM.PAINT) {
         VarSetCapacity(PAINTSTRUCT, A_PtrSize + (4 * 7) + 32 + (A_PtrSize - 4), 0)
         LBDC := DllCall("USer32.dll\BeginPaint", "Ptr", hWnd, "Ptr", &PAINTSTRUCT, "UPtr")

         WM_GETFONT := 0x0031
         SendMessage, %WM_GETFONT%, 0, 0, , ahk_id %hWnd%
         Font := ErrorLevel
         HFONT := DllCall("Gdi32.dll\SelectObject", "Ptr", LBDC, "Ptr", Font, "UPtr")

         DllCall("Gdi32.dll\SetBkMode", "Ptr", LBDC, "Int", 1) ; TRANSPARENT

         VarSetCapacity(RECT, 16, 0)
         DllCall("GetClientRect", "Ptr", hWnd, "Ptr", &RECT)

         W := This.Width ,    H := This.Height

         ;DllCall("Gdi32.dll\BitBlt", "Ptr", LBDC, "Int", 0, "Int", 0, "Int", This.Width, "Int", This.Height, "Ptr", This.SELDC, "Int", 0, "Int", 0, "UInt", SRCCOPY := 0x00CC0020)
         DllCall("Gdi32.dll\GdiAlphaBlend", "Ptr", LBDC, "Int", 0, "Int", 0, "Int", W, "Int", H , "Ptr", This.SELDC, "Int", 0, "Int", 0, "Int", W, "Int", H , "UInt", (This.Transparency << 16))

         ControlGetText, Txt,, ahk_id %hWnd%
         Len := StrLen(Txt)
            
         DllCall("Gdi32.dll\SetTextColor", "Ptr", LBDC, "UInt", 0xFFFFFF)
         DllCall("User32.dll\DrawText", "Ptr", LBDC, "Ptr", &Txt, "Int", Len, "Ptr", &RECT, "UInt", 0x0840)
         DllCall("User32.dll\OffsetRect", "Ptr", &RECT, "Int", 0, "Int", This.Height)
      }

      Return DllCall("Comctl32.dll\DefSubclassProc", "Ptr", hWnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam)

   }

   SetRedraw(Mode) {
      ;FileAppend, Redraw! `n,*
      Static WM_SETREDRAW := 0x000B
      Mode := !!Mode
      This.Drawing := Mode
      SendMessage, %WM_SETREDRAW%, %Mode%, 0, , % "ahk_id " . This.HLB
      If (Mode)
         WinSet, Redraw, , % "ahk_id " . This.HLB
      Return True
   }
}

image.png
image.png (9.25 KiB) Viewed 723 times

Code: Select all

DllCall("Gdi32.dll\GdiAlphaBlend", "Ptr", LBDC, "Int", 0, "Int", 0, "Int", W, "Int", H , "Ptr", This.SELDC, "Int", 0, "Int", 0, "Int", W, "Int", H , "UInt", (This.Transparency << 16))
The hBitmap from Imagen() and the hBitmap from your previous function SetTransparency, look different, which one is correct?
What I'm missing?
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: [GDI]How to create a bitmap with opacity?

Post by SKAN » 16 Jun 2021, 07:06

Code: Select all

..."UInt", (255 << 16))
Imagen() always returns a PARGB bitmap in which case last parameter for GdiAlphaBlend() should be 0x01FF0000
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

Re: [GDI]How to create a bitmap with opacity?

Post by pv007 » 16 Jun 2021, 07:23

Perfect, Thank you Skan!!!
Post Reply

Return to “Ask for Help (v1)”