[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
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

[GDI]How to create a bitmap with opacity?

10 Jun 2021, 19:43

Code: Select all

CreateBITMAP(Width, Height, Radius, Color) {
   	BkColor := 0xFFF
   	BkColor .= Color
   	FileAppend, BkColor: %BkColor% `n,*

	pBitmap := Gdip_CreateBitmap( Width, Height ) 
  	G := Gdip_GraphicsFromImage( pBitmap ) 
	Gdip_SetSmoothingMode( G , 4 )
	Brush := Gdip_BrushCreateSolid( BkColor )
   

   	Gdip_FillRoundedRectangle(G, Brush, 0, 0, Width, Height, Radious)
   	Gdip_DeleteBrush( Brush )
	Gdip_DeleteGraphics( G )
	return pBitmap
}
I have found this function here at the forum to create a pBitmap with GDI.

Would like to ask, how to add a new option to it "opacity"?

I don't know if opacity is the right word, I mean a result similar to this effect in Photoshop:

A 70x70 red picture:
T1.png
T1.png (249 Bytes) Viewed 1896 times
Now with 50% opacity:
T2.png
T2.png (251 Bytes) Viewed 1896 times


The option I refer to, in photoshop:
Spoiler
If there's any way to set opacity/transparency in a already existing hBitmap also would help
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

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

10 Jun 2021, 23:55

A couple of examples:

Code: Select all

pToken := Gdip_Startup()

hbm := CreateHBitmap(w := 300, h := 220, 0x77FF0000)

hdc := CreateCompatibleDC()
obj := SelectObject(hdc, hbm)
Gui, -Caption +E0x80000 +ToolWindow +AlwaysOnTop +hwndhGui
Gui, Show, NA
UpdateLayeredWindow(hGui, hdc, 500, 400, w, h)

SelectObject(hdc, obj)
DeleteObject(hbm)
DeleteDC(hdc)
Gdip_Shutdown(pToken)

CreateHBitmap(width, height, color) {
   hBitmap := CreateDIBSection(width, height,,, pBits)
   Loop % width*height
      NumPut(color, pBits + (A_Index - 1)*4, "UInt")
   Return hBitmap
}

Code: Select all

pToken := Gdip_Startup()

pBitmap := CreateBitmap(0x77FF0000, w := 300, h := 220, 15)

hbm := CreateDIBSection(w, h)
hdc := CreateCompatibleDC()
obj := SelectObject(hdc, hbm)
G := Gdip_GraphicsFromHDC(hdc)
Gdip_DrawImage(G, pBitmap, 0, 0, w, h)
Gui, -Caption +E0x80000 +ToolWindow +AlwaysOnTop +hwndhGui
Gui, Show, NA
UpdateLayeredWindow(hGui, hdc, 500, 400, w, h)

SelectObject(hdc, obj)
DeleteObject(hbm)
DeleteDC(hdc)
Gdip_DeleteGraphics(G)
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)

CreateBitmap(color, w, h, r := 0) {
   pBitmap := Gdip_CreateBitmap(w, h)
   G := Gdip_GraphicsFromImage(pBitmap)
   pBrush := Gdip_BrushCreateSolid(color)
   Gdip_SetSmoothingMode(G, AntiAlias := 4)
   Gdip_FillRoundedRectangle(G, pBrush, 0, 0, w - !!r, h - !!r, r)
   DeleteObject(pBrush)
   Gdip_DeleteGraphics(G)
   Return pBitmap
}
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

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

11 Jun 2021, 00:57

@teadrinker please an example not using layered window

I tried:

Code: Select all

color := 0x199FF0000
pBitmap := CreateBitmap(color, w := 300, h := 220, 0)

HB := Gdip_CreateHBITMAPFromBitmap(pBitmap)

Gui, Font, s16
Gui, Add, Text,,TEXT TEXT TEXT TEXT
Gui, Add, Picture, x0 y0 +BackgroundTrans,% "HBITMAP:" . HB
Gui, Show, w300 h220, TEST

Gui, 2:Show, w300 h220,

pBitmap2 := CreateBitmap(color, w := 300, h := 220, 0)

hbm := CreateDIBSection(w, h)
hdc := CreateCompatibleDC()
obj := SelectObject(hdc, hbm)
G := Gdip_GraphicsFromHDC(hdc)
Gdip_DrawImage(G, pBitmap2, 0, 0, w, h)

Gui, 3: +hwndhGui +E0x80000
Gui, 3:Show
UpdateLayeredWindow(hGui, hdc, 500, 400, w, h)
But the color looks different than the color in the layered window, also how do you specify no transparency in the color parameter?
0x99FF0000

99 is the transparency level, right? how do I tell it no transparency in case of need?
0x100FF0000 gives a color totally different
Spoiler
User avatar
boiler
Posts: 16768
Joined: 21 Dec 2014, 02:44

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

11 Jun 2021, 01:57

pv007 wrote: But the color looks different than the color in the layered window
You used a transparency (actually opacity) of 0x99, while teadrinker used 0x77, so I don’t know why you would expect them to look the same.

pv007 wrote: also how do you specify no transparency in the color parameter?
0x99FF0000

99 is the transparency level, right? how do I tell it no transparency in case of need?
0x100FF0000 gives a color totally diferent
99 (as specified here) is the alpha channel, which is where you indicate transparency. It is more correctly viewed as opacity because higher numbers are more opaque. 100 is not full opacity/no transparency. These are hexadecimal numbers, and the max is 0xFF (255 in decimal), not 100. No transparency/full opacity for this color is 0xFFFF0000.

Full opacity is 0xFF (255 decimal). Full transparency is 0x00 (0). 50% transparency is 0x80 (128). What you specified with 0x99 (153 decimal) is 60% opacity or 40% transparency.
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

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

11 Jun 2021, 02:28

Hello Boiler, thanks for the explanation about the alpha channel!

When i said looks different, i was referring to the color in the GUI and the layered window, this colors:
Spoiler
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

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

11 Jun 2021, 08:59

pv007 wrote: i was referring to the color in the GUI and the layered window
The color in the GUI looks differently since the GUI has its own color that shines through the semitransparent Picture.
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

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

12 Jun 2021, 22:17

@just me and when you already have an existing bitmap, how do you load it into a gui and apply transparency on it? (No layered window please)

@teadrinker can you provide me another example of instead creating a new bitmap, applying transparency to a existing one?
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

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

13 Jun 2021, 03:06

As I understand, transparency can be added only if HBitmap is 32 bits per pixel:

Code: Select all

SetBatchLines, -1
imgWithoutTransparency := A_WinDir . "\Web\Wallpaper\Windows\img0.jpg"
opacity := 0x77

hBitmap := LoadPicture(imgWithoutTransparency, "GDI+ w300 h-1")
SetTransparency(hBitmap, opacity)

hBitmapWithoutTransparency := LoadPicture(imgWithoutTransparency, "GDI+ w300 h-1")
Gui, Color, White
Gui, Add, Text,, Background
Gui, Add, Pic, xp yp +BackgroundTrans, HBITMAP: %hBitmap%
Gui, Add, Text,, This text won't be visible
Gui, Add, Pic, xp yp +BackgroundTrans, HBITMAP: %hBitmapWithoutTransparency%
Gui, Show
Return

GuiClose:
   ExitApp
   
SetTransparency(hBitmap, opacity) {
   static DIB_RGB_COLORS := 0
   VarSetCapacity(BITMAP, byteCount := 4*4 + A_PtrSize*2, 0)
   DllCall("GetObject", "Ptr", hBitmap, "Int", byteCount, "Ptr", &BITMAP)
   width := NumGet(BITMAP, 4, "UInt"), height := NumGet(BITMAP, 8, "UInt")
   bpp := NumGet(BITMAP, 18, "UShort")
   if (bpp != 32)
      throw "Bits per pixel: " . bpp . ", must be 32"
   
   if pBits := NumGet(BITMAP, 4*4 + A_PtrSize) {
      Loop % width * height
         NumPut(opacity, pBits + (A_Index - 1)*4 + 3, "UChar")
   }
   else {
      VarSetCapacity(BITMAPINFO, size := 4*10, 0)
      NumPut(size, BITMAPINFO)
      NumPut(width, BITMAPINFO, 4), NumPut(-height, BITMAPINFO, 8)
      NumPut(1, BITMAPINFO, 12), NumPut(bpp, BITMAPINFO, 14)
      VarSetCapacity(Bits, width * 4 * height, 0)
      hDC := DllCall("CreateCompatibleDC", "Ptr", 0, "Ptr")
      hObj := DllCall("SelectObject", "Ptr", hDC, "Ptr", hBitmap)
      DllCall("GetDIBits", "Ptr", hDC, "Ptr", hBitmap, "UInt", 0, "UInt", height, "Ptr", &Bits, "Ptr", &BITMAPINFO, "UInt", DIB_RGB_COLORS)
      Loop % width * height
         NumPut(opacity, &Bits + (A_Index - 1)*4 + 3, "UChar")
      DllCall("SetDIBits", "Ptr", hDC, "Ptr", hBitmap, "UInt", 0, "UInt", height, "Ptr", &Bits, "Ptr", &BITMAPINFO, "UInt", DIB_RGB_COLORS)
      DllCall("SelectObject", "Ptr", hDC, "Ptr", hObj)
      DllCall("DeleteDC", "Ptr", hDC)
   }
}
pv007
Posts: 93
Joined: 20 Jul 2020, 23:50

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

13 Jun 2021, 03:38

Hi Teadrinker, i'm testing the script, is it really applying "transparency"? i can see the text beneath the picture, but it looks strange, looks like it's only changing the picture brightness
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

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

13 Jun 2021, 05:52

Hi @teadrinker

I'd assume LoadPicture(..., "GDI+") returns PARGB bitmap (@lexikos could confirm).
You can't set constant Alpha value in a PARGB without adjusting RGB values accordingly, I suppose.
 
image.png
image.png (4.78 KiB) Viewed 1674 times
 

Code: Select all

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

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

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

Gui, New, -MinimizeBox, Opacity
Gui, Color, White
Gui, Margin, 20, 20
Gui, Add, Picture,xm, T1.png
Gui, Add, Text, xm y+0, Background
Gui, Add, Picture, xp+32 BackgroundTrans, T2.png

Gui, Add, Picture,xm, T1.png
Gui, Add, Text, xm y+0, Background

hBM := LoadPicture("T1.png", "GDI+")
SetTransparency(hBM, 127)
Gui, Add, Picture,xp+32 BackgroundTrans, HBITMAP:%hBM%
Gui, Show



SetTransparency(hBitmap, opacity) {
   static DIB_RGB_COLORS := 0
   VarSetCapacity(BITMAP, byteCount := 4*4 + A_PtrSize*2, 0)
   DllCall("GetObject", "Ptr", hBitmap, "Int", byteCount, "Ptr", &BITMAP)
   width := NumGet(BITMAP, 4, "UInt"), height := NumGet(BITMAP, 8, "UInt")
   bpp := NumGet(BITMAP, 18, "UShort")
   if (bpp != 32)
      throw "Bits per pixel: " . bpp . ", must be 32"

   if pBits := NumGet(BITMAP, 4*4 + A_PtrSize) {
      Loop % width * height
         NumPut(opacity, pBits + (A_Index - 1)*4 + 3, "UChar")
   }
   else {
      VarSetCapacity(BITMAPINFO, size := 4*10, 0)
      NumPut(size, BITMAPINFO)
      NumPut(width, BITMAPINFO, 4), NumPut(-height, BITMAPINFO, 8)
      NumPut(1, BITMAPINFO, 12), NumPut(bpp, BITMAPINFO, 14)
      VarSetCapacity(Bits, width * 4 * height, 0)
      hDC := DllCall("CreateCompatibleDC", "Ptr", 0, "Ptr")
      hObj := DllCall("SelectObject", "Ptr", hDC, "Ptr", hBitmap)
      DllCall("GetDIBits", "Ptr", hDC, "Ptr", hBitmap, "UInt", 0, "UInt", height, "Ptr", &Bits, "Ptr", &BITMAPINFO, "UInt", DIB_RGB_COLORS)
      Loop % width * height
         NumPut(opacity, &Bits + (A_Index - 1)*4 + 3, "UChar")
      DllCall("SetDIBits", "Ptr", hDC, "Ptr", hBitmap, "UInt", 0, "UInt", height, "Ptr", &Bits, "Ptr", &BITMAPINFO, "UInt", DIB_RGB_COLORS)
      DllCall("SelectObject", "Ptr", hDC, "Ptr", hObj)
      DllCall("DeleteDC", "Ptr", hDC)
   }
}
 

@pv007 : My Imagen() will do this if you pass a colormatrix in options.
I will try to implement this as a built-in feature. (Edit: Done)
lexikos
Posts: 9556
Joined: 30 Sep 2013, 04:07
Contact:

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

13 Jun 2021, 06:35

The bitmap returned by LoadPicture with GDI+ is either the one created by GdipCreateHBITMAPFromBitmap, or a copy created with CopyImage. I would guess that any alpha channel is not retained, based on the presence of a "background color" parameter. I think the parameters and return value are only documented for the C++ wrapper, and even there the details are sparse.
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

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

13 Jun 2021, 08:16

SKAN wrote: You can't set constant Alpha value in a pARGB without adjusting RGB values accordingly, I suppose.
But I see correct RGB values:

Code: Select all

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

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

VarSetCapacity(BITMAP, byteCount := 4*4 + A_PtrSize*2, 0)
DllCall("GetObject", "Ptr", hBitmap, "Int", byteCount, "Ptr", &BITMAP)
width := NumGet(BITMAP, 4, "UInt"), height := NumGet(BITMAP, 8, "UInt")
bpp := NumGet(BITMAP, 18, "UShort")
if (bpp != 32)
   throw "Bits per pixel: " . bpp . ", must be 32"

if pBits := NumGet(BITMAP, 4*4 + A_PtrSize) {
   Loop % width * height {
      MsgBox, % "red: "   . Format("{:#x}", NumGet(pBits + (A_Index - 1)*4 + 2, "UChar")) . "`n"
              . "green: " . Format("{:#x}", NumGet(pBits + (A_Index - 1)*4 + 1, "UChar")) . "`n"
              . "blue: "  . Format("{:#x}", NumGet(pBits + (A_Index - 1)*4 + 0, "UChar"))
   }
}
In the format Format32bppPArgb R, G, B are premultiplied, the formula is:

Code: Select all

factor := alpha/0xFF
PARGB := alpha << 24 | R*factor << 16 | G*factor << 8 | B*factor
If alpha is 0xff, factor is 1.
Am I wrong? @lexikos
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

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

13 Jun 2021, 09:11

Got it, I had to change RGB values depending on the pixel format. There should be a universal way for all 32-bit formats. I'll think about it.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

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

13 Jun 2021, 10:35

lexikos wrote:
13 Jun 2021, 06:35
The bitmap returned by LoadPicture with GDI+ is either the one created by GdipCreateHBITMAPFromBitmap, or a copy created with CopyImage. I would guess that any alpha channel is not retained, based on the presence of a "background color" parameter.
As far as I've tested LoadPicture with GDI+ always returns an alpha bitmap.
Transparency/Alpha transparency (if any) is well preserved.
Please clarify whether LoadPicture() returned alpha bitmap is in ARGB or PARGB pixel format. Thanks.

Forum doesn't allow .bmp file so i have zipped mono.bmp ( 653x200 1bpp bitmap ).
You may use the following script to test it.

Code: Select all

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

hbm := LoadPicture("mono.bmp", "GDI+")
MsgBox % IsAlphaBitmap(hbm) ; True

IsAlphaBitmap(sBM) {                                        ; v0.95 by SKAN on D39C/D39O @ tiny.cc/t80920
Local
  VarSetCapacity(BITMAP, 32, 0)
  Res := DllCall("GetObject", "Ptr",sBM, "Int",A_PtrSize=8? 32:24, "Ptr",&BITMAP)
  Bpp := NumGet(BITMAP,18,"UShort")
  If (Res=0|| Bpp<32)
    Return 0

  W := NumGet(BITMAP,04,"UInt"), Plane := NumGet(BITMAP,16,"UShort"),  WBytes := NumGet(BITMAP,12,"UInt")
  H := NumGet(BITMAP,08,"UInt"), Bytes := WBytes*H,                    HalfSz := Bytes/2
  VarSetCapacity(BITMAPINFO, 40, 0), pBits:=0
  NumPut(Bpp,NumPut(Plane,NumPut(0-H,NumPut(W,NumPut(40,BITMAPINFO,"Int"),"Int"),"Int"),"Short"),"Short")
  tBM := DllCall("CreateDIBSection"
               , "Ptr",0, "Ptr",&BITMAPINFO, "Int",0, "PtrP",pBits, "Ptr",0, "Int", 0, "Ptr")
  tDC := DllCall("CreateCompatibleDC", "Ptr",0, "Ptr"),  DllCall("SaveDC", "Ptr",tDC)
  sDC := DllCall("CreateCompatibleDC", "Ptr",0, "Ptr"),  DllCall("SaveDC", "Ptr",sDC)
  DllCall("SelectObject", "Ptr",tDC, "Ptr",tBM)
  DllCall("SelectObject", "Ptr",sDC, "Ptr",sBM)
  DllCall("GdiAlphaBlend", "Ptr",tDC, "Int",0, "Int",0, "Int",W, "Int",H
                         , "Ptr",sDC, "Int",0, "Int",0, "Int",W, "Int",H, "Int",0x01FF0000)
  DllCall("RestoreDC", "Ptr",sDC, "Int",-1),             DllCall("DeleteDC", "Ptr",sDC)
  DllCall("RestoreDC", "Ptr",tDC, "Int",-1),             DllCall("DeleteDC", "Ptr",tDC)
  IsAplha := NumGet(pBits+0,"UInt") ? 1
          :  !(DllCall("ntdll\RtlCompareMemory", "Ptr",pBits, "Ptr",pBits+1, "Ptr",Bytes-1)=Bytes-1)
  DllCall("DeleteObject", "Ptr",tBM)
Return IsAplha
}
Attachments
mono.zip
(1.82 KiB) Downloaded 118 times
teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

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

13 Jun 2021, 13:04

SKAN wrote: My Imagen() will do this if you pass a colormatrix in options.
I will try to implement this as a built-in feature. (Edit: Done)
Even from hBitmap?
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

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

13 Jun 2021, 13:18

teadrinker wrote:
13 Jun 2021, 13:04
SKAN wrote: My Imagen() will do this if you pass a colormatrix in options.
I will try to implement this as a built-in feature. (Edit: Done)
Even from hBitmap?
Yes. filename can be "HBITMAP:" . hBM .. or "HBITMAP:*" . hBM if you want Imagen() to use a copy of hBitmap
.. either case it will delete the hBitmap you pass to it.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

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

13 Jun 2021, 15:07

teadrinker wrote:
13 Jun 2021, 14:32
Yes, it works, great! :)
:thumbup:

PS:
I had incorrectly uploaded my work folder instead of release folder.
If there is a Desktop_SlideShow.ahk in contents don't try it. It wasn't well tested and still in development.
lexikos
Posts: 9556
Joined: 30 Sep 2013, 04:07
Contact:

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

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.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: deets, imstupidpleshelp, Jaroz, mikeyww, OrangeCat and 146 guests