Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

GDI+ standard library 1.45 by tic


  • Please log in to reply
1385 replies to this topic
Sven
  • Members
  • 22 posts
  • Last active: Apr 05 2012 08:03 AM
  • Joined: 03 Aug 2011
Hey,

I'm having troubles keeping the alpha channel of a matched pixel intact when replacing non matching pixels with another color. The following code is borrowed from "unknown" (<!-- l --><a class="postlink-local" href="http://www.autohotkey.com/community/viewtopic.php?f=1&t=32078&p=368881#p368881">viewtopic.php?f=1&t=32078&p=368881#p368881</a><!-- l -->) and modified to allow for shade variation of the target pixel color.

#SingleInstance, Force
#NoEnv
SetBatchLines, -1
#Include, Gdip.ahk

File1 = test2.bmp

backcolor := "0x09bc22" ; greenish color I want to keep...
variance := 40 ; ... which can vary 40 shades
newcolor  := "0xff000000" ; replace anything else with deep blackness

;a := (backcolor & 0xff000000) >> 24 ; I'm looking for any alpha value so no need to specify a specific one
r := (backcolor & 0x00ff0000) >> 16
g := (backcolor & 0x0000ff00) >> 8
b := backcolor & 0x000000ff

If !pToken := Gdip_Startup()
{
	MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
	ExitApp
}

pBitmapFile1 := Gdip_CreateBitmapFromFile(File1)

Width := Gdip_GetImageWidth(pBitmapFile1), Height := Gdip_GetImageHeight(pBitmapFile1)
x=0
y=0

loop %width%
{
	loop %height%
	{
		color:=Gdip_GetPixel(pBitmapFile1, x, y)
		a_ := (color & 0xff000000) >> 24
		r_ := (color & 0x00ff0000) >> 16
		g_ := (color & 0x0000ff00) >> 8
		b_ := color & 0x000000ff
		
		if !((r_ > r-variance && r_ < r+variance) && (g_ > g-variance && g_ < g+variance) && (b_ > b-variance && b_ < b+variance))
		;if !((a_ > a-255 && a_ < a+255) && (r_ > r-variance && r_ < r+variance) && (g_ > g-variance && g_ < g+variance) && (b_ > b-variance && b_ < b+variance))
			Gdip_SetPixel(pBitmapFile1, x, y, newcolor)
		y++
	}
	x++
	y=0
}

Gdip_SaveBitmapToFile(pBitmapFile1, "FinalImage.bmp")
Gdip_DisposeImage(pBitmapFile1)
Gdip_DeleteGraphics(G)
Gdip_Shutdown(pToken)
ExitApp
Return

It works well in that it's only keeping the pixels matching the color specified ( +- shade variation), but it dismisses any alpha channel information of these pixels which I also want to keep.

Any hints?

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
Sorry all....I'm finding these new forums impossible to use and so haven't been on here very often!Without being able to search the forums, code expansion or code colouring being the most important things, it is too hard to help out.

feel

You have managed to get a bitmap of a window, but you are not doing anything with it

Sven

Check the image has the right colour depth. Look for lockbits examples using the gdi+ library to achieve what you are wanting

Sorry for the half hearted responses but this website is giving me a headache! :wink:

  • Guests
  • Last active:
  • Joined: --
This is more like a request than ask for help, but I don't know GDI at all, if someone helps that would be nice
I want to show an image with transparency on top of a GUI, half in half out like the screenshot..

Posted Image

Any idea?
Thanks anyway

kenn
  • Members
  • 407 posts
  • Last active: Jan 14 2015 08:16 PM
  • Joined: 11 Oct 2010
I hope that link can give you an idea <!-- l --><a class="postlink-local" href="http://www.autohotkey.com/community/viewtopic.php?f=2&t=82381">viewtopic.php?f=2&t=82381</a><!-- l -->
My Scripts
Ain’t No Shame in Asking for Help!

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
I'm having an issue extracting a bitmap from Shell32.dll in Windows 7 64 bit:
GetInfo()

{

	bitmap := Gdip_CreateBitmapFromFile("C:\Windows\System32\shell32.dll", 222)

	msgbox bitmap %bitmap%

	hbitmap := Gdip_CreateHBITMAPFromBitmap(bitmap)

	msgbox hbitmap %hbitmap%

	return hbitmap

}
It works fine on x86, but on x64 I get ERROR_RESOURCE_ENUM_USER_STOP and then ERROR_INVALID_CURSOR_HANDLE (in DrawIconEx()) in Gdip_CreateBitmapFromFile(). I'm using an x64 version of this library of course (Btw tic, can you post it on the first post?). It appears that a hIcon is first acquired but then later rejected (function returns -2). Any ideas?

lblb
  • Members
  • 120 posts
  • Last active: Dec 02 2015 08:05 AM
  • Joined: 22 May 2012
Hi,

I'm trying to use Gdip_Pixelsearch to find where a specific color can be found on an inactive window but I'm having a hard time making it work. I modified the example from here:
<!-- l --><a class="postlink-local" href="http://www.autohotkey.com/community/viewtopic.php?p=526047">viewtopic.php?p=526047</a><!-- l -->
I've searched extensively but just can't find an example of pixel search in an area of a window using GDI+ as the window is inactive (out of screen).

What I want to do:
- Search for a specific color (let's say black 0x000000) in a specific region of an inactive window

What I have so far:
- I thought the code below would at least give me the location of the first pixel of that color. However, it says it doesn't find the color even if it's present on the window (whether the window is active or inactive; the window's name is Navigator and it's of ahk_class sfl_window_class)
- Even if the code below worked, I still need to modify it so that it searches in a specific region of the window.

Any help would be greatly appreciated. Thanks in advance!

#NoEnv  
SendMode Input 
SetWorkingDir %A_ScriptDir%  

#include gdip.ahk

pToken := GDIP_StartUp()
pBitmap := Gdip_BitmapFromHWND(hwnd := WinExist("Navigator ahk_class sfl_window_class"))
if !Gdip_PixelSearch(pBitmap, ARGB := 0x000000, x, y)
   {
   MsgBox, Pixel %ARGB% found at (%x%, %y%)
   }
else
   MsgBox, Pixel %ARGB% not found
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
return

;#####################################################################################

Gdip_PixelSearch(pBitmap, ARGB, ByRef x, ByRef y)
{
   static _PixelSearch
   if !_PixelSearch
   {
      MCode_PixelSearch := "8B44241099535583E2035603C233F6C1F80239742418577E388B7C24148B6C24248B5424188D1C85000000008D64240033C085"
      . "D27E108BCF3929743183C00183C1043BC27CF283C60103FB3B74241C7CDF8B4424288B4C242C5F5EC700FFFFFFFF5DC701FFFFFFFF83C8FF5BC38B4C2"
      . "4288B54242C5F890189325E5D33C05BC3"

      VarSetCapacity(_PixelSearch, StrLen(MCode_PixelSearch)//2)
      Loop % StrLen(MCode_PixelSearch)//2      ;%
         NumPut("0x" SubStr(MCode_PixelSearch, (2*A_Index)-1, 2), _PixelSearch, A_Index-1, "char")
   }
   Gdip_GetImageDimensions(pBitmap, Width, Height)
   if !(Width && Height)
      return -1

   if (E1 := Gdip_LockBits(pBitmap, 0, 0, Width, Height, Stride1, Scan01, BitmapData1))
      return -2

   x := y := 0
   E := DllCall(&_PixelSearch, "uint", Scan01, "int", Width, "int", Height, "int", Stride1, "uint", ARGB, "int*", x, "int*", y)
   Gdip_UnlockBits(pBitmap, BitmapData1)
   return (E = "") ? -3 : E
}


tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
fragman

Yeh I have been planning on integrating the x86 and x64 libraries. Maybe if we can get this forum fixed and stop being a nightmare to use then I'll start to push out a few updates I have. Gdip_CreateBitmapFromFile is already a very dirty way to get bitmaps from resources. It was only meant as a temporary solution. It would need to be looked through to write properly and then convert to x64

lblb

First thing I have to say is that 0x000000 is not black ;) That is a transparent pixel which couldn't possibly exist on your screen

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
Why not put it on GitHub?

lblb
  • Members
  • 120 posts
  • Last active: Dec 02 2015 08:05 AM
  • Joined: 22 May 2012
Hi tic,

Thank you very much for your answer! And thank you very much for maintaining this library.

Your comment initially threw me off (especially since I'm completely new to color coding) but I realized that I was using the Hex code for black and not the argb code. I got it to work by using 0xFF000000. So thank you very much for your help.
Is there any way to adapt the code I'm using in order to use Hex color codes instead, as all the other programs I have use Hex color coding?
Also, I still don't know how to look in a specific region of a window.

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
Yep, converting RGB to ARGB is as simple as

ARGB := 0xff000000 | RGB

If the pixelSearch doesn't currently implement the ability to search in an area. you could simply do this yourself by taking creating a new bitmap using the rectangle required with

Gdip_CloneBitmapArea(pBitmap, x, y, w, h)

and search that instead

lblb
  • Members
  • 120 posts
  • Last active: Dec 02 2015 08:05 AM
  • Joined: 22 May 2012
This works great! Thanks tic for all your help, much appreciated. I may be back fro more questions soon but for now these seem to work just as I needed. I am really amazed by this library and by your dedication to help others.

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
Is there a way to find out if a variable contains a HBITMAP or HICON?
I want to be able to assign both of them to text controls with a single function, but it seems that they require different messages and styles.

Edit: Found GetObjectType(), would you include it in the library for future users?

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
Further issue on AHK_L Unicode x64:
#include <gdip>
pToken:=gdip_startup()
pbitmap := Gdip_CreateBitmapFromFile("C:\Projekte\Autohotkey\7plus\128.png")
Gdip_SetBitmapToClipboard(pBitmap)
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(ApplicationState.pToken)
Works on AHK_L Unicode x86 but not on x64. I suspect that Gdip_SetBitmapToClipboard() is not yet compatible with x64 since Gdip_CreateBitmapFromFile() works for png files. I will post more incompatibilities as I find them, in the meantime I'm happy for any suggested fixes.

Edit: The method used in the WinClip library works. I have not examined it in depth but I will use that method for the time being.

fragman
  • Members
  • 1591 posts
  • Last active: Nov 12 2012 08:51 PM
  • Joined: 13 Oct 2009
I believe I have fixed Gdip_CreateBitmapFromFile() for x64 by considering the struct sizes and paddings correctly:
Gdip_CreateBitmapFromFile(sFile, IconNumber=1, IconSize="")

{

	SplitPath, sFile,,, ext

	if ext in exe,dll

	{

		Sizes := IconSize ? IconSize : 256 "|" 128 "|" 64 "|" 48 "|" 32 "|" 16

		VarSetCapacity(buf, 8 + 3 * A_PtrSize)

		Loop, Parse, Sizes, |

		{

			DllCall("PrivateExtractIcons", "str", sFile, "int", IconNumber-1, "int", A_LoopField, "int", A_LoopField, "ptr*", hIcon, "ptr*", 0, "uint", 1, "uint", 0)

			if !hIcon

				continue



			if !DllCall("GetIconInfo", "ptr", hIcon, "ptr", &buf)

			{

				DestroyIcon(hIcon)

				continue

			}

			hbmColor := NumGet(buf, 8 + 2 * A_PtrSize)

			hbmMask  := NumGet(buf, 8 + A_PtrSize)



			if !(hbmColor && DllCall("GetObject", "ptr", hbmColor, "int", 24, "ptr", &buf))

			{

				DestroyIcon(hIcon)

				continue

			}

			break

		}

		if !hIcon

			return -1



		Width := NumGet(buf, 4, "int"),  Height := NumGet(buf, 8, "int")

		hbm := CreateDIBSection(Width, -Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)



		if(!DllCall("DrawIconEx", "ptr", hdc, "int", 0, "int", 0, "ptr", hIcon, "uint", Width, "uint", Height, "uint", 0, "ptr", 0, "uint", 3))

		{

			DestroyIcon(hIcon)

			return -2

		}



		VarSetCapacity(dib, 84 + 3 * A_PtrSize)

		DllCall("GetObject", "ptr", hbm, "int", 84 + 3 * A_PtrSize, "ptr", &dib) ; sizeof(DIBSECTION) = 76+2*(A_PtrSize=8?4:0)+2*A_PtrSize

		Stride := NumGet(dib, 12, "int")

		Bits := NumGet(dib, 20 + (A_PtrSize = 8 ? 4 : 0)) ; padding



		DllCall("gdiplus\GdipCreateBitmapFromScan0", "int", Width, "int", Height, "int", Stride, "int", 0x26200A, "ptr", Bits, "ptr*", pBitmapOld)

		pBitmap := Gdip_CreateBitmap(Width, Height), G := Gdip_GraphicsFromImage(pBitmap)

		Gdip_DrawImage(G, pBitmapOld, 0, 0, Width, Height, 0, 0, Width, Height)

		SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)

		Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmapOld)

		DestroyIcon(hIcon)

	}

	else

		DllCall("gdiplus\GdipCreateBitmapFromFile", "wstr", sFile, "ptr*", pBitmap)

	return pBitmap

}
Did not test that code branch yet, only used the else part :D

guest3456
  • Members
  • 1704 posts
  • Last active: Nov 19 2015 11:58 AM
  • Joined: 10 Mar 2011
will 32bit codes of AHK source not work on 64bit windows? i was under the impression that 64bit systems were backwards compatible and 32bit applications still worked