Gdip_ExpandColor - Remove fringe from images with transparent color

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
boiler
Posts: 17095
Joined: 21 Dec 2014, 02:44

Gdip_ExpandColor - Remove fringe from images with transparent color

03 Jul 2020, 11:52

I wrote this in response to an Ask For Help post, and I thought I would post it here in case others find it useful. It grows the specified color by one pixel in all directions which helps remove fringe that can result when using a transparent color.
Before and after example

Function:

Code: Select all

/*
	Gdip_ExpandColor grows the specified color by one pixel in all directions.
	Helps remove fringe that can result when using a transparent color.

	pBitMap is the pointer to your bitmap which will be modified directly

	color parameter can be RGB or BGR and can include alpha channel or not.
	Alpha channel will be added/changed to be 0xFF.

	Example: Gdip_ExpandColor(pBitmap, 0xA024BA)

	by boiler
	2020-07-03
*/

Gdip_ExpandColor(pBitmap, color) {
	if (A_PtrSize = 4)
		expandColorMCodeBase64 := ""
		. "2,x86:VYnlg+wQgU0MAAAA/8dF+AAAAADrWcdF/AEAAADrRItF"
		. "+A+vRRCJwotF/AHQiUX0i0X0jRSFAAAAAItFCAHQiwA7RQx1GY"
		. "tF9AX///8/jRSFAAAAAItFCAHCi0UMiQKDRfwBi0X8O0UQfLSD"
		. "RfgBi0X4O0UUfJ/HRfgAAAAA61/HRfwAAAAA60eLRRArRfyJwo"
		. "tF+A+vRRAB0IlF9ItF9AX///8/jRSFAAAAAItFCAHQiwA7RQx1"
		. "FItF9I0UhQAAAACLRQgBwotFDIkCg0X8AYtFEIPoATtF/H+ug0"
		. "X4AYtF+DtFFHyZx0X4AAAAAOtcx0X8AAAAAOtHi0UUK0X4D69F"
		. "EInCi0X8AdCJRfSLRfSNFIUAAAAAi0UIAdCLADtFDHUZi1UQi0"
		. "X0AdCNFIUAAAAAi0UIAcKLRQyJAoNF/AGLRfw7RRB8sYNF+AGL"
		. "RRSD6AE7Rfh/mcdF+AEAAADrW8dF/AAAAADrRotF+A+vRRCJwo"
		. "tF/AHQiUX0i0X0jRSFAAAAAItFCAHQiwA7RQx1G4tFEItV9CnC"
		. "idCNFIUAAAAAi0UIAcKLRQyJAoNF/AGLRfw7RRB8soNF+AGLRf"
		. "g7RRR8nZDJww=="
	else
		expandColorMCodeBase64 := ""
		. "2,x64:VUiJ5UiD7BBIiU0QiVUYRIlFIESJTSiBTRgAAAD/x0X4"
		. "AAAAAOtfx0X8AQAAAOtKi0X4D69FIInCi0X8AdCJRfSLRfRIjR"
		. "SFAAAAAEiLRRBIAdCLADtFGHUci0X0g+gBicBIjRSFAAAAAEiL"
		. "RRBIAcKLRRiJAoNF/AGLRfw7RSB8roNF+AGLRfg7RSh8mcdF+A"
		. "AAAADrZcdF/AAAAADrTYtFICtF/InCi0X4D69FIAHQiUX0i0X0"
		. "g+gBicBIjRSFAAAAAEiLRRBIAdCLADtFGHUXi0X0SI0UhQAAAA"
		. "BIi0UQSAHCi0UYiQKDRfwBi0Ugg+gBO0X8f6iDRfgBi0X4O0Uo"
		. "fJPHRfgAAAAA62THRfwAAAAA60+LRSgrRfgPr0UgicKLRfwB0I"
		. "lF9ItF9EiNFIUAAAAASItFEEgB0IsAO0UYdR6LVSCLRfQB0InA"
		. "SI0UhQAAAABIi0UQSAHCi0UYiQKDRfwBi0X8O0UgfKmDRfgBi0"
		. "Uog+gBO0X4f5HHRfgBAAAA62PHRfwAAAAA606LRfgPr0UgicKL"
		. "RfwB0IlF9ItF9EiNFIUAAAAASItFEEgB0IsAO0UYdSCLRSCLVf"
		. "QpwonQicBIjRSFAAAAAEiLRRBIAcKLRRiJAoNF/AGLRfw7RSB8"
		. "qoNF+AGLRfg7RSh8lZBIg8QQXcOQ"

	expandColorMCode := BentschiMCode(expandColorMCodeBase64)
	Gdip_GetImageDimensions(pBitmap, w, h)
	Gdip_LockBits(pBitmap, 0, 0, w, h, stride, scan, bitmapData)
	DllCall(expandColorMCode, "uint", scan, "uint", color, "int", w, "int", h, "cdecl")
	Gdip_UnlockBits(pBitmap, bitmapData)
}

BentschiMCode(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)
}

Demo:

Code: Select all

#Include <gdip_all>
#Include Gdip_ExpandColor.ahk

pToken := Gdip_Startup()

pBitmap := Gdip_CreateBitmapFromFile("peter_griffin.png")
Gdip_ExpandColor(pBitmap, 0xc040c0)
Gdip_SaveBitmapToFile(pBitmap, "peter_griffin_trimmed.png")
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)

Gui, +HwndGuiID
Gui, Color, c040c0
Gui, Add, Picture,, peter_griffin.png
Gui, Add, Picture, x+5 yp, peter_griffin_trimmed.png
Gui, Show
WinSet, TransColor, c040c0, ahk_id %GuiID%
return

Esc::ExitApp

Image used for demo

Source for MCode:

Code: Select all

unsigned int Gdip_ExpandColor(unsigned int *bitmap, unsigned int targetColor, int w, int h)
{
	int x, y;
	unsigned int p;

	targetColor = targetColor | 0xFF000000; // add A channel

	// replace all the colors to the left of the target color:
	for (y = 0; y < h; ++y)	{
		for (x = 1; x < w; ++x) {
			p = x + y * w;
			if (bitmap[p] == targetColor)
				bitmap[p - 1] = targetColor;
		}
	}

	// replace all the colors to the right of the target color:
	for (y = 0; y < h; ++y)	{
		for (x = 0; x < w - 1; ++x) {
			p = w - x + y * w;
			if (bitmap[p - 1] == targetColor)
				bitmap[p] = targetColor;
		}
	}

	// replace all the colors below the target color:
	for (y = 0; y < h - 1; ++y)	{
		for (x = 0; x < w; ++x) {
			p = x + (h - y) * w;
			if (bitmap[p] == targetColor)
				bitmap[p + w] = targetColor;
		}
	}

	// replace all the colors above the target color:
	for (y = 1; y < h; ++y)	{
		for (x = 0; x < w; ++x) {
			p = x + y * w;
			if (bitmap[p] == targetColor)
				bitmap[p - w] = targetColor;
		}
	}
}
Last edited by boiler on 03 Jul 2020, 14:44, edited 3 times in total.
User avatar
boiler
Posts: 17095
Joined: 21 Dec 2014, 02:44

Re: Gdip_ExpandColor

03 Jul 2020, 13:40

Edited the first post to fix an error and replace sample with a better example.
User avatar
boiler
Posts: 17095
Joined: 21 Dec 2014, 02:44

Re: Gdip_ExpandColor - Remove fringe from images with transparent color

07 Jul 2020, 09:01

You’re welcome. It may not be needed often, but when the situation arises, it can make a big difference.
User avatar
andymbody
Posts: 919
Joined: 02 Jul 2017, 23:47

Re: Gdip_ExpandColor - Remove fringe from images with transparent color

27 Oct 2023, 17:26

This is really cool @boiler... thanks for sharing... I'm sure it will come in handy...
User avatar
boiler
Posts: 17095
Joined: 21 Dec 2014, 02:44

Re: Gdip_ExpandColor - Remove fringe from images with transparent color

29 Oct 2023, 23:28

Thanks for the feedback. Glad you like it.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: Killin and 85 guests