Transparent png on a dark background

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
think
Posts: 136
Joined: 09 Feb 2014, 05:20

Transparent png on a dark background

Post by think » 16 Jan 2022, 09:25

Hi, I have troubles showing the transparent png picture on a dark background. The picture has a gradual transparency on the edges (anti aliasing) to ensure smooth edges but those are colored white on a dark background. When opened in the image editor, it shows correctly.

My simple code is below. Do I miss something? Any tip is highly appreciated.

Code: Select all

gui, -caption +alwaysontop +toolwindow 
gui, color, ffffff
gui, add, picture, BackgroundTrans, test.png
gui, show, noactivate, MyWin
winset, transcolor, ffffff, MyWin
return
image.png
image.png (5.14 KiB) Viewed 897 times

User avatar
boiler
Posts: 16772
Joined: 21 Dec 2014, 02:44

Re: Transparent png on a dark background

Post by boiler » 16 Jan 2022, 09:49

Using WinSet to make a certain color transparent only makes those pixels that are that exact color transparent. The fringe colors are not pure white, so they are left alone.

Using the function Gdip_ExpandColor(), you can expand the pure color of the @ symbol so it covers the fringe pixels. This is how the script looks with this modification:

Code: Select all

#Include <gdip_all>
#Include Gdip_ExpandColor.ahk

pToken := Gdip_Startup()
pBitmap := Gdip_CreateBitmapFromFile("test.png")
Gdip_ExpandColor(pBitmap, 0x4C4C4C)
Gdip_SaveBitmapToFile(pBitmap, "test_modified.png")
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)

gui, -caption +alwaysontop +toolwindow 
gui, color, ffffff
gui, add, picture, BackgroundTrans, test_modified.png
gui, show, noactivate, MyWin
winset, transcolor, ffffff, MyWin
return

Esc::ExitApp

And the result as displayed in the GUI over a black background is:
display.png
display.png (1.17 KiB) Viewed 869 times

Of course, you don't need to include the function and the Gdip library in your final script. You can just use it once to produce the modified image, then just have your script display the modified image instead of the original.

think
Posts: 136
Joined: 09 Feb 2014, 05:20

Re: Transparent png on a dark background

Post by think » 16 Jan 2022, 11:15

Thanks for a quick response, sounds promising but unfortunately I still get the same result. What am I doing wrong? My PNG file was created in Photoshop and saved with PNG-24 option.
Also, if Gdip can transform the file, can I do it in Photoshop too?

Code: Select all

#Include gdip_all.ahk
#Include Gdip_ExpandColor.ahk

pToken := Gdip_Startup()
pBitmap := Gdip_CreateBitmapFromFile("test.png")
Gdip_ExpandColor(pBitmap, 0x4C4C4C)
Gdip_SaveBitmapToFile(pBitmap, "test_modified.png")
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)

gui, -caption +alwaysontop +toolwindow 
gui, color, ffffff
gui, add, picture, BackgroundTrans, test_modified.png
gui, show, noactivate, MyWin
winset, transcolor, ffffff, MyWin
return

Esc::ExitApp

User avatar
boiler
Posts: 16772
Joined: 21 Dec 2014, 02:44

Re: Transparent png on a dark background

Post by boiler » 16 Jan 2022, 11:30

think wrote: ...unfortunately I still get the same result. What am I doing wrong? My PNG file was created in Photoshop and saved with PNG-24 option.
Can you post the resulting image that the script created, called "test_modified.png"?

think wrote: Also, if Gdip can transform the file, can I do it in Photoshop too?
The methods I've tried to use in Photoshop always fills with a smoothed/anti-aliased edge, so it doesn't help. I can select using the magic selection tool with a low tolerance so it includes all the fringe pixels, but then when I fill, it fills with a smoothed edge. If you know you to fill the entire selection with just the pure color (and therefore, jagged edges), that would work.

think
Posts: 136
Joined: 09 Feb 2014, 05:20

Re: Transparent png on a dark background

Post by think » 16 Jan 2022, 12:58

Thanks for your reply - here is the generated file.
image.png
image.png (5.93 KiB) Viewed 805 times
Attachments
test_modified.png
test_modified.png (4.3 KiB) Viewed 805 times

User avatar
Hellbent
Posts: 2103
Joined: 23 Sep 2017, 13:34

Re: Transparent png on a dark background

Post by Hellbent » 16 Jan 2022, 13:34

If you want to have a window with transparency you should use a Layered window +E0x80000 ( WS_EX_LAYERED )

Here is a working example using a class I have for working with layered windows. You can find a number of examples on the forum of using a layered window if you want to find the base code needed to use them.

Code: Select all

#Include Gdip.ahk
#SingleInstance, Force
GDIP_STARTUP()

pBitmap := Gdip_CreateBitmapFromFile( "test.png" )

Gui1 := New PopUpWindow( { AutoShow: 1 , W: w := GDIP_GetImageWidth( pBitmap ) , H: h := GDIP_GetImageHeight( pBitmap ) , X: ( A_ScreenWidth - w ) / 2 , Y: ( A_ScreenHeight - h ) / 2 , Options: " -DPIScale +AlwaysOnTop " } )
Gui1.DrawBitmap( pBitmap , { X: 0 , Y: 0 , W: Gui1.W , H: Gui1.H } , dispose := 1 , AutoUpdate := 1 )

return
GuiContextMenu:
*ESC::ExitApp

RAlt::PopUpWindow.Helper()

;####################################################################################################################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################
class PopUpWindow	{
;PopUpWindow v2
;Date Written: Oct 28th, 2021
;Written By: Hellbent aka CivReborn
;SpcThanks: teadrinker , malcev 
	static Index := 0 , Windows := [] , Handles := [] , EditHwnd , HelperHwnd
	__New( obj := "" ){
		This._SetDefaults()
		This.UpdateSettings( obj )
		This._CreateWindow()
		This._CreateWindowGraphics()
		if( This.AutoShow )
			This.ShowWindow( This.Title )
	}
	_SetDefaults(){
		This.X := 10
		This.Y := 10
		This.W := 10
		This.H := 10
		This.Smoothing := 2
		This.Options := " -DPIScale +AlwaysOnTop "
		This.AutoShow := 0
		This.GdipStartUp := 0
		This.Title := ""
		
		This.Controls := []
		This.Handles := []
		This.Index := 0 
	}
	AddTrigger( obj ){
		local k , v , cc , bd
		
		This.Controls[ ++This.Index ] := { 	X:		10
										,	Y:		10
										,	W:		10
										,	H:		10	}
		for k, v in obj
			This.Controls[ This.Index ][ k ] := obj[ k ] 
		cc := This.Controls[ This.Index ]
		Gui, % This.Hwnd ":Add", Text, % "x" cc.X " y" cc.Y " w" cc.W " h" cc.H " hwndhwnd"
		This.Handles[ hwnd ] := This.Index
		This.Controls[ This.Index ].Hwnd := hwnd
		return hwnd
		
	}
	DrawTriggers( color := "0xFFFF0000" , AutoUpdate := 0 ){
		local brush , cc 
		Brush := Gdip_BrushCreateSolid( color ) 
		Gdip_SetSmoothingMode( This.G , 3 )
		loop, % This.Controls.Length()	{
			cc := This.Controls[ A_Index ]
			Gdip_FillRectangle( This.G , Brush , cc.x , cc.y , cc.w , cc.h )
		
		}
		Gdip_DeleteBrush( Brush )
		Gdip_SetSmoothingMode( This.G , This.Smoothing )
		if( AutoUpdate )
			This.UpdateWindow()
	}
	UpdateSettings( obj := "" , UpdateGraphics := 0 ){
		local k , v
		if( IsObject( obj ) )
			for k, v in obj
				This[ k ] := obj[ k ]
		( This.X = "Center" ) ? ( This.X := ( A_ScreenWidth - This.W ) / 2 ) 	
		( This.Y = "Center" ) ? ( This.Y := ( A_ScreenHeight - This.H ) / 2 ) 	
		if( UpdateGraphics ){
			This._DestroyWindowsGraphics()
			This._CreateWindowGraphics()
		}
	}
	_CreateWindow(){
		local hwnd
		Gui , New, % " +LastFound +E0x80000 hwndhwnd -Caption  " This.Options ;+E0x80000 = WS_EX_LAYERED
		PopUpWindow.Index++
		This.Index := PopUpWindow.Index
		PopUpWindow.Windows[ PopUpWindow.Index ] := This
		This.Hwnd := hwnd
		PopUpWindow.Handles[ hwnd ] := PopUpWindow.Index
		if( This.GdipStartUp && !PopUpWindow.pToken )
			PopUpWindow.pToken := GDIP_STARTUP()
	}
	_DestroyWindowsGraphics(){
		SelectObject( This.hdc , This.obm )
		DeleteObject( This.hbm )
		DeleteDC( This.hdc )
	}
	_CreateWindowGraphics(){
		This.hbm := CreateDIBSection( This.W , This.H )
		This.hdc := CreateCompatibleDC()
		This.obm := SelectObject( This.hdc , This.hbm )
		This.G := Gdip_GraphicsFromHDC( This.hdc )
		Gdip_SetSmoothingMode( This.G , This.Smoothing )
	}
	ShowWindow( Title := "" ){
		Gui , % This.Hwnd ":Show", % "x" This.X " y" This.Y " w" This.W " h" This.H " NA", % Title
	}
	HideWindow(){
		Gui , % This.Hwnd ":Hide",
	}
	UpdateWindow(){
		UpdateLayeredWindow( This.hwnd , This.hdc , This.X , This.Y , This.W , This.H )
	}
	ClearWindow( AutoUpdate := 0 ){
		Gdip_GraphicsClear( This.G )
		if( Autoupdate )
			This.UpdateWindow()
	}
	DrawBitmap( pBitmap , obj , dispose := 1 , AutoUpdate := 0 ){
		Gdip_DrawImage( This.G , pBitmap , obj.X , obj.Y , obj.W , obj.H )
		if( dispose )
			Gdip_DisposeImage( pBitmap )
		if( Autoupdate )
			This.UpdateWindow()
	}
	PaintBackground( color := "0xFF000000" , AutoUpdate := 0 ){
		if( isObject( color ) ){
			Brush := Gdip_BrushCreateSolid( ( color.HasKey( "Color" ) ) ? ( color.Color ) : ( "0xFF000000" ) ) 
			if( color.Haskey( "Round" ) )
				Gdip_FillRoundedRectangle( This.G , Brush , color.X , color.Y , color.W , color.H , color.Round )
			else
				Gdip_FillRectangle( This.G , Brush , color.X , color.Y , color.W , color.H ) 
		}else{
			Brush := Gdip_BrushCreateSolid( color ) 
			Gdip_FillRectangle( This.G , Brush , -1 , -1 , This.W + 2 , This.H + 2 ) 
		}
		Gdip_DeleteBrush( Brush )
		if( AutoUpdate )
			This.UpdateWindow()
	}
	DeleteWindow( GDIPShutdown := 0 ){
		Gui, % This.Hwnd ":Destroy"
		SelectObject( This.hdc , This.obm )
		DeleteObject( This.hbm )
		DeleteDC( This.hdc )
		Gdip_DeleteGraphics( This.G )
		hwnd := This.Hwnd
		for k, v in PopUpWindow.Windows[ Hwnd ]
			This[k] := ""
		PopUpWindow.Windows[ Hwnd ] := ""
		if( GDIPShutdown ){
			Gdip_Shutdown( PopUpWindow.pToken )
			PopUpWindow.pToken := ""
		}
	}
	_OnClose( wParam ){
		if( wParam = 0xF060 ){	;SC_CLOSE ;[ clicking on the gui close button ]
			Try{
				Gui, % PopUpWindow.HelperHwnd ":Destroy"
				SoundBeep, 555
			}
		}
	}
	CreateCachedBitmap( pBitmap , Dispose := 0 ){
		local pCachedBitmap
		if( This.CachedBitmap )
			This.DisposeCachedbitmap()
		DllCall( "gdiplus\GdipCreateCachedBitmap" , "Ptr" , pBitmap , "Ptr" , this.G , "PtrP" , pCachedBitmap )
		This.CachedBitmap := pCachedBitmap
		if( Dispose )
			Gdip_DisposeImage( pBitmap )
	}
	DrawCachedBitmap( AutoUpdate := 0 ){
		DllCall( "gdiplus\GdipDrawCachedBitmap" , "Ptr" , this.G , "Ptr" , This.CachedBitmap , "Int" , 0 , "Int" , 0 )
		if( AutoUpdate )
			This.UpdateWindow()
	}
	DisposeCachedbitmap(){
		DllCall( "gdiplus\GdipDeleteCachedBitmap" , "Ptr" , This.CachedBitmap )
	}
	Helper(){
		local hwnd , MethodList := ["__New","UpdateSettings","ShowWindow","HideWindow","UpdateWindow","ClearWindow","DrawBitmap","PaintBackground","DeleteWindow" , "AddTrigger" , "DrawTriggers", "CreateCachedBitmap" , "DrawCachedBitmap" , "DisposeCachedbitmap" ]
		Gui, New, +AlwaysOnTop +ToolWindow +HwndHwnd
		PopUpWindow.HelperHwnd := hwnd
		Gui, Add, Edit, xm ym w250 r1 Center hwndhwnd, Gui1
		PopUpWindow.EditHwnd := hwnd
		loop, % MethodList.Length()	
			Gui, Add, Button, xm y+1 w250 r1 gPopUpWindow._HelperClip, % MethodList[ A_Index ]
		Gui, Show,,
		OnMessage( 0x112 , This._OnClose.Bind( hwnd ) )
	}
	_HelperClip(){
		local ClipList 
		
		GuiControlGet, out, % PopUpWindow.HelperHwnd ":", % PopUpWindow.EditHwnd	
		
		ClipList := 		{ 	__New: 					" := New PopUpWindow( { X: 0 , Y: 0 , W: A_ScreenWidth , H: A_ScreenHeight , Options: "" -DPIScale +AlwaysOnTop "" } )"
							,	UpdateSettings:			".UpdateSettings( { X: """" , Y: """" , W: """" , H: """" } , UpdateGraphics := 0 )"
							,	ShowWindow:				".ShowWindow( Title := """" )"
							,	HideWindow:				".HideWindow()"
							,	UpdateWindow:			".UpdateWindow()"
							,	ClearWindow:			".ClearWindow( AutoUpdate := 0 )"
							,	DrawBitmap:				".DrawBitmap( pBitmap := """" , { X: 0 , Y: 0 , W: " Out ".W , H: " Out ".H } , dispose := 1 )"
							,	PaintBackground:		".PaintBackground( color := ""0xFF000000"" )  "  ";{ Color: ""0xFF000000"" , X: 2 , Y: 2 , W: " Out ".W - 4 , H: " Out ".H - 4 , Round: 10 }"
							,	DeleteWindow:			".DeleteWindow( GDIPShutdown := 0 )"
							,	AddTrigger:				".AddTrigger( { X: """" , Y: """" , W: """" , H: """" , Value: """" , Label: """" , BoundClass: """" , BoundMethod: """" } )"	
							,	DrawTriggers:			".DrawTriggers( color := ""0xFFFF0000"" , AutoUpdate := 0 )"	
							,	CreateCachedBitmap:		".CreateCachedBitmap( pBitmap , Dispose := 0 )"	
							,	DrawCachedBitmap: 		".DrawCachedBitmap( AutoUpdate := 0 )"	
							,	DisposeCachedbitmap:	".DisposeCachedbitmap()"	}
							
		clipboard := Out ClipList[ A_GuiControl ]
		
	}
}
;####################################################################################################################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################

User avatar
boiler
Posts: 16772
Joined: 21 Dec 2014, 02:44

Re: Transparent png on a dark background

Post by boiler » 16 Jan 2022, 13:36

Oh, your original is already on a transparent background? Try it with a white background (in the image itself) by either cropping the left side of the image in your first post, or put a white background behind it in Photoshop and save it as a png again. Then use that as the original image for my function to operate on.

think
Posts: 136
Joined: 09 Feb 2014, 05:20

Re: Transparent png on a dark background

Post by think » 16 Jan 2022, 14:06

@Hellibent, thank you. It works great.

@boiler, thanks. Still no luck unfortunately. But I'm still intrigued with your solution. I created the file with a white background in Photoshop and used it in the script, not sure what's wrong. Please find the file attached.
test.png
test.png (3.88 KiB) Viewed 778 times

User avatar
boiler
Posts: 16772
Joined: 21 Dec 2014, 02:44

Re: Transparent png on a dark background

Post by boiler » 16 Jan 2022, 15:11

I see the issue. The image you are posting now has a different grey value than what you posted before. It was 0x4C4C4C, and now it's 0x545454. You have to identify the exact color you want the function to expand. So you need to change this line in the script:

Code: Select all

Gdip_ExpandColor(pBitmap, 0x4C4C4C)
to:

Code: Select all

Gdip_ExpandColor(pBitmap, 0x545454)
Or you can use the original image where the color was 0x4C4C4C. Either way, there can't be that mismatch.

think
Posts: 136
Joined: 09 Feb 2014, 05:20

Re: Transparent png on a dark background

Post by think » 16 Jan 2022, 15:36

Ok, thanks, it works.
The problem with this approach is that it replaces gradual transparency with the solid color and therefore makes the character bolder and introduces the jagged edges. But good to know, thanks!

User avatar
boiler
Posts: 16772
Joined: 21 Dec 2014, 02:44

Re: Transparent png on a dark background

Post by boiler » 16 Jan 2022, 16:43

Yes, that's what I was saying about the WinSet approach. It is only going to make pixels of the pure color transparent, so you can't make a gradual transition. That approach and my function is better suited for when the image itself is on a color you want to make transparent, so you can't cleanly remove it, like the example picture in the thread the function came from.

Post Reply

Return to “Ask for Help (v1)”