GDI+ Gdip_AlphaMask() not preserving png transparency

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

GDI+ Gdip_AlphaMask() not preserving png transparency

19 Mar 2018, 07:25

Firstly, is Tic still active and is GDI+ lib being maintained? I noticed Gdip_AlphaMask() function is missing in Gdip.ahk and i dont know why.
Its a very useful function.
Secondly, the function works great but theres a problem with it, the transparency from a png image becomes white. It supposed to just cut off edges or make it round if a solid image is being rendered or if the image is too large.
Is there a way around this or am i doing something wrong?

Heres an example:

Code: Select all

#NoEnv
;#Warn
SendMode Input
SetWorkingDir %A_ScriptDir%
#SingleInstance, Force
#Persistent
SetBatchLines, -1

; Comment out if in your standard lib.
#Include, %A_ScriptDir%\Gdip_All.ahk

If !pToken := Gdip_Startup() {
	MsgBox, 48, Winamp Widget: gdiplus error!, Gdiplus failed to start. Please ensure you have the proper gdiplus on your system.`n`nWinamp Widget will now exit.
	exitapp
}
OnExit, Exit

ImageW := 100 ; End image width. Here you specify how large the image is going to be displayed (Gui width essentially).
ImageH := 100 ; End image height. Here you specify how large the image is going to be displayed (Gui width essentially).
Padding := 50 ; In percent! Padding 0 - 100, 0 = cubic, 100 = round (is making cubes rounder called padding?)
AspectRatioType := 2 ; 0 = Resize freely, 1 = by largest dimension between width and height, 2 = by smallest dimension between width and height.

	hbm := CreateDIBSection(ImageW, ImageH)
	hdc := CreateCompatibleDC()
	obm := SelectObject(hdc, hbm)
	
	G := Gdip_GraphicsFromHDC(hdc)
	Gdip_SetSmoothingMode(G, 4)

	Gui, Base: -Caption +E0x80000 +OwnDialogs ;+Owner
	Gui, Base: +LastFound +AlwaysOnTop
	LastParentHwnd := hwndBase := WinExist()
	Gui, Base: Show, NA
	
	pBrush := Gdip_BrushCreateSolid(0x0100ff00)
	Gdip_FillRectangle(G, pBrush, 0, 0, ImageW, ImageH)
	Gdip_DeleteBrush(pBrush)
	
	UpdateLayeredWindow(hwndBase, hdc, A_ScreenWidth-ImageW-200, 200, ImageW, ImageH)
	Gdip_GraphicsClear(G)
	
	Gui, 1: -Caption +E0x80000 +OwnDialogs ;+Owner
	Gui, 1: +LastFound +AlwaysOnTop
	Gui, 1: +E0x10
	Gui, 1: +Parent%LastParentHwnd%
	hwnd1 := WinExist()
	Gui, 1: Show, NA
	
	pBrush := Gdip_BrushCreateSolid(0xff00ff00)
	Gdip_FillRectangle(G, pBrush, 0, 0, ImageW, ImageH)
	Gdip_DeleteBrush(pBrush)
	
	UpdateLayeredWindow(hwnd1, hdc, 0, 0, ImageW, ImageH)
	Gdip_GraphicsClear(G)
	
	OnMessage(0x201, "WM_LBUTTONDOWN")
return

GuiDropFiles:
	Image := A_GuiEvent
	
	pBitmap := Gdip_CreateBitmapFromFile(Image), Gdip_GetDimensions(pBitmap, W, H)
	ImgW := ImageW
	ImgH := ImageH
	Resize(ImgW, ImgH, W, H, AspectRatioType)
	
	pBitmapMask := Gdip_CreateBitmap(W, H), G2 := Gdip_GraphicsFromImage(pBitmapMask), Gdip_SetSmoothingMode(G2, 4),Gdip_SetInterpolationMode(G2, 7)
	pBrush := Gdip_BrushCreateSolid(0xff00ff00)
	CanvasW := W
	CanvasH := H
	CanvasOffsetX := 0
	CanvasOffsetY := 0
	if (CanvasW > CanvasH) {
		CanvasW := CanvasH
		CanvasOffsetX := (W/2)-(H/2)
		NewPadding := ((CanvasW/2)/100) * Clamp(Padding,0,100)
	} else {
		CanvasH := CanvasW
		CanvasOffsetY := (W/2)-(H/2)
		NewPadding := ((CanvasH/2)/100) * Clamp(Padding,0,100)
	}
	
	Gdip_FillRoundedRectangle(G2, pBrush, CanvasOffsetX, CanvasOffsetY, CanvasW, CanvasH, NewPadding)
	Gdip_DeleteBrush(pBrush), Gdip_DeleteGraphics(G2)
	pBitmapNew := Gdip_AlphaMask(pBitmap, pBitmapMask, 0, 0, 0)
	
	DrawW := (ImageW/2)-ImgW/2
	DrawH := (ImageH/2)-ImgH/2
	Gdip_DrawImage(G, pBitmapNew, DrawW, DrawH, ImgW, ImgH, 0, 0, W, H)
	
	UpdateLayeredWindow(hwnd1, hdc, 0, 0, ImageW, ImageH)
	Gdip_GraphicsClear(G)
	Gdip_DisposeImage(pBitmapNew), Gdip_DisposeImage(pBitmap), Gdip_DisposeImage(pBitmapMask)
return



F1::reload
^Esc::exitapp

Exit:
	SelectObject(hdc, obm)
	DeleteObject(hbm)
	DeleteDC(hdc)
	Gdip_DeleteGraphics(G)
	Gdip_DeleteGraphics(G2)
	
	Gdip_Shutdown(pToken)
	exitapp
return



WM_LBUTTONDOWN() {
	PostMessage, 0xA1, 2
}

; Resize by theimmersion
Resize(byref NewW, byref NewH, OrigW, OrigH, aspectRatio=0) {
	if (aspectRatio = 1 or aspectRatio = 2) {
		if NewW and NewH {
			if aspectRatio = 1
				(OrigW-NewW) > (OrigH-NewH) ? NewH := round(OrigH/OrigW*NewW) : NewW := round(OrigW/OrigH*NewH)
			else if aspectRatio = 2
				(OrigW-NewW) < (OrigH-NewH) ? NewH := round(OrigH/OrigW*NewW) : NewW := round(OrigW/OrigH*NewH)
		}
	}
	NewW := NewW = "" ? round(OrigW/OrigH*NewH) : NewW
	NewH := NewH = "" ? round(OrigH/OrigW*NewW) : NewH
}

; Clamp by theimmersion
Clamp(ByRef Val, Min, Max) {
	If (Val < Min)
		Val := Min
	If (Val > Max)
		Val := Max
	return Val
}

; by Tic. http://www.autohotkey.com/board/topic/103475-gdi-cutting-anti-aliasing/#entry638772
MCode(mcode)
{
  static e := {1:4, 2:1}, c := (A_PtrSize=8) ? "x64" : "x86"
  if (!regexmatch(mcode, "^([0-9]+),(" c ":|.*?," c ":)([^,]+)", m))
    return
  if (!DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", 0, "uint*", s, "ptr", 0, "ptr", 0))
    return
  p := DllCall("GlobalAlloc", "uint", 0, "ptr", s, "ptr")
  if (c="x64")
    DllCall("VirtualProtect", "ptr", p, "ptr", s, "uint", 0x40, "uint*", op)
  if (DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", p, "uint*", s, "ptr", 0, "ptr", 0))
    return p
  DllCall("GlobalFree", "ptr", p)
}


Gdip_AlphaMask(pBitmap, pBitmapMask, x, y, invert=0) {
    static _AlphaMask := MCode("
(LTrim Join
1,x86:518b4424249983e2035355568d0c028b4424349983e203c1f902578d3402c1fe02837c2444000f85980000008b4424
308944243885c00f8e340100008d1c8d000000000faf4c24408d14b500000000895c24348b7424208b5c241c89542444034c
243c8d2c8e8b4c242c8b742434669085c97e3b8b7c24188bd52b7c24208bc38bf18b0c178d40043348fc8d520481e1ffffff
003348fc894afc83ee0175e38b4424388b4c242c8b5424448b74243403ee03da83e8018944243875b45f5e5d33c05b59c38b
5424308954241085d20f8e9c0000008b7c24208d04b5000000008b6c241c894424348d048d000000000faf4c24408b5c2434
894424388bf0034c243c8d048f8b4c242c894424440f1f400085c97e4b8b5c24188bd02bdf8bf58bf98b068d760425000000
ff8d5204b9000000ff2bc88b441afc25ffffff000bc8894afc83ef0175d98b4424448b5424108b4c242c8b5c24348b742438
8b7c242003c603eb83ea01894424448954241075a05f5e5d33c05b59c3,x64:48895c24084c8944241848895424105556574
1544155415641574883ec108b8424900000004c8bc248637424789983e2034c8be903c2c1f8024c63d08b842488000000998
3e20303c2c1f80283bc24a8000000004863c848890c240f85a60000008b8c248000000085c90f8e3a0100004c63bc24a0000
0004e8d3495000000004c63a424980000004533c9458bd9498bea498bd88bf94885f67e584c8b5424604b8d1439480faf142
4488bc3492bd34903d448c1e202492bd04c03d24e8d042a488bd60f1f4000660f1f840000000000418b0c003308488d40048
1e1ffffff003348fc41894c02fc4883ea0175e24c8b4424584c03dd4903de49ffc14883ef017594e9a30000008b842480000
00085c00f8e940000004c63b424a00000004533c94c63bc2498000000418bd94c8b642458498bea8bf84885f67e634c8b542
4604b8d1431480fafd14c8bdb4c2bda4d2bdf49c1e3024a8d043a4d2bdd4c8d0485000000004d03dc4d03c5488bd64d2bd54
38b04184d8d400425000000ffb9000000ff2bc8418b40fc25ffffff000bc843894c02fc4883ea0175d6488b0c244803dd49f
fc14883ef01758c33c0488b5c24504883c410415f415e415d415c5f5e5dc3
)")

    Gdip_GetDimensions(pBitmap, w1, h1), Gdip_GetDimensions(pBitmapMask, w2, h2)
    pBitmapNew := Gdip_CreateBitmap(w1, h1)
    if !pBitmapNew
        return -1

    E1 := Gdip_LockBits(pBitmap, 0, 0, w1, h1, Stride1, Scan01, BitmapData1)
    E2 := Gdip_LockBits(pBitmapMask, 0, 0, w2, h2, Stride2, Scan02, BitmapData2)
    E3 := Gdip_LockBits(pBitmapNew, 0, 0, w1, h1, Stride3, Scan03, BitmapData3)
    if (E1 || E2 || E3)
        return -2

    E := DllCall(_AlphaMask, "ptr", Scan01, "ptr", Scan02, "ptr", Scan03, "int", w1, "int", h1, "int", w2, "int", h2, "int", Stride1, "int", Stride2, "int", x, "int", y, "int", invert, "cdecl int")
    Gdip_UnlockBits(pBitmap, BitmapData1), Gdip_UnlockBits(pBitmapMask, BitmapData2), Gdip_UnlockBits(pBitmapNew, BitmapData3)

    return (E = "") ? -3 : pBitmapNew
}
You can just drag and drop some .png image that has transparency onto it.
The rendering and everything else relevant to Gdip_AlphaMask() function is in GuiDropFiles: subroutine and the function itself of course.

EDIT
Setting x and/or y (i assume offsets) in Gdip_AlphaMask() to anything other than 0 crashes AHK v1.1. :(
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_AlphaMask() not preserving png transparency

20 Mar 2018, 05:06

Wonder if it could be possible to detect if an image has transparency and if so, create a solid image from any pixels from that image.
Add the usual solid for roundness as well to it and then apply the alpha mask on the final image.
That way, you could get a round profile image and its original transparency.
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: GDI+ Gdip_AlphaMask() not preserving png transparency

20 Mar 2018, 05:29

Maybe you could create a suitable path and the use "Gdip_SetClipPath(pGraphics, Path, CombineMode=0)" before drawing the image.Transparency is kept but getting the path correct need some serious thinking...........

There is an example by nnnik but it did not work when i tried it (the clipped corners where not correct) but i guess it is worth a try :) if you really need it.

nnnik's code:
https://autohotkey.com/boards/viewtopic.php?t=33410
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: GDI+ Gdip_AlphaMask() not preserving png transparency

20 Mar 2018, 06:26

GDIp i still being maintained - or rather he is currently rewriting it using objects.
guest2345 is maintaining an version that works for both AHK_L and V2 since you are calling your #include gdip_all.ahk you should be using it.

Gdip_Alpha Mask is not part of the original Gdip implementation because it is an addition that tic made by himself.
It seems like he only wants to keep the things that are closely related to the original function in gdip.ahk
While the main library is still in active maintenance I'm not so sure about any of the additions or if anybody even has the source for that machine code anymore.
Recommends AHK Studio
User avatar
noname
Posts: 515
Joined: 19 Nov 2013, 09:15

Re: GDI+ Gdip_AlphaMask() not preserving png transparency

20 Mar 2018, 07:00

LinearSpoon has compiled it to 64bit and you also source code here:
https://autohotkey.com/boards/viewtopic.php?f=5&t=39077
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_AlphaMask() not preserving png transparency

20 Mar 2018, 07:10

I hope when Tic does a rewrite, hell add some missing functions. Also hope he could somehow make some stuff easier to do.
I also just notice that Gdip_AlphaMask() is a bit finicky. The crop cuts out a few bits more then it should. What ever i try, it does not seem to crop it right.
Like 1-2 pixels get chopped off more on the bottom and right part of the image. The idea is to have a function collection for image manipulation. You give the image and specify what should be done and get the result in an easier way. Essentially trying to wrap up original functions into fewer ones. Everything works except Gdip_AlphaMask(). Ill figure something out i hope.
User avatar
theimmersion
Posts: 181
Joined: 09 Jul 2016, 08:34
Location: Serbia

Re: GDI+ Gdip_AlphaMask() not preserving png transparency

25 Mar 2018, 09:15

Im experimenting with nnnik's code you posted, noname.
Seems like its closer to what i need but has one drawback currently. The edges are rough. No smoothing going on but it seems it does exactly what i need.
Ill try to make a nicer wrapper and try figure out the anti-aliasing (i guess?).

For direct reference @ https://autohotkey.com/boards/viewtopic.php?t=33410 by nnnik

Code: Select all

#Include <Gdip_All>
#NoEnv

roundSize := 100

pToken  := Gdip_Startup()
pBitmap := Gdip_CreateBitmapFromFile( "test.jpg" )
pTarget := Gdip_CreateBitmap( w := Gdip_getImageWidth( pBitmap ), h := Gdip_getImageHeight( pBitmap ) )
pGraphics := Gdip_GraphicsFromImage( pTarget )

pPath   := Gdip_CreatePath()

Gdip_AddPathEllipse( pPath, 0, 0, roundSize * 2, roundSize * 2 )
Gdip_AddPathEllipse( pPath, 0, h - roundSize * 2, roundSize * 2, roundSize * 2 )
Gdip_AddPathEllipse( pPath, w - roundSize * 2, 0, roundSize * 2, roundSize * 2 )
Gdip_AddPathEllipse( pPath, w - roundSize * 2, h - roundSize * 2, roundSize * 2, roundSize * 2 )

Gdip_SetClipRect( pGraphics, roundSize, 0, w - roundSize * 2, h )
Gdip_SetClipRect( pGraphics, 0, roundSize, w, h - roundSize * 2, 2 )
Gdip_SetClipPath( pGraphics, pPath, 2 )

Gdip_DrawImage( pGraphics, pBitmap )
Gdip_SaveBitmapToFile( pTarget, "out2.png" )


Gdip_DeletePath( pPath )
Gdip_DeleteGraphics( pGraphics )
Gdip_DisposeImage( pBitmap )
Gdip_DisposeImage( pTarget )

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: gongnl, Google [Bot], Rohwedder and 238 guests