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
Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
Dunno where to post ( was hard for me and can be usefull ), maybe that will help or it's a bug, I played with matrix for understand color transformation (with a lot of problem) and I tried threshold with some properties (8bit)... I hope this Binarization will hope for you , without use lockbit feature and palette for dithering , so seems very fast :)
#NoEnv
OnExit, Exit
pToken := Gdip_Startup()

If !FileExist("temp.gif")
	UrlDownloadToFile, % "http://www.autohotkey.com/docs/images/AutoHotkey_logo.gif", temp.gif

pBitmap := Gdip_CreateBitmapFromFile("temp.gif")
Gdip_GetDimensions(pBitmap, w, h)

Gui, 1:Add, Slider, x0 y0 w%w% Range0-256 vMySlider gMyLabel, % MySlider:=128
Gui, 1: Add, Picture, x0 y24 w%w% h%h% 0xE hwndMyPic
Gui, 1: Show, w%w% h%h% , % "threshold:" MySlider

pBrush0 := Gdip_BrushCreateSolid(0xFFFFFFFF)
pBitmap0 := Gdip_CreateBitmap(w, h), G0 := Gdip_GraphicsFromImage(pBitmap0), Gdip_SetSmoothingMode(G0, 3)
Gdip_FillRectangle(G0, pBrush0, 0, 0, w, h)

MyLabel:
R := 0.299 , G := 0.587 , B := 0.114 , k:=1000
; k is a fix for ARGB32 format, we need B*k*255 > 255, same for R and G if smaller, else it's not a binary threshold but a mask, 
R:=R*k*255 , G:=G*k*255 , B:=B*k*255 , T:=-k*(MySlider-1)

m:= R "|" R "|" R "|0|0|"
m.= G "|" G "|" G "|0|0|"
m.= B "|" B "|" B "|0|0|"
m.= 0 "|" 0 "|" 0 "|1|0|"
m.= T "|" T "|" T "|0|1"

;m := "76245|76245|76245|0|0|149685|149685|149685|0|0|29070|29070|29070|0|0|0|0|0|1|0|-127000|-127000|-127000|0|1"
Gdip_DrawImage(G0, pBitmap, 0, 0, w, h, 0, 0, w, h, m)

hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap0)
SetImage(MyPic, hBitmap)
DeleteObject(hBitmap)
WinSetTitle, % "threshold:" MySlider
return

;Gdip_LockBits(pBitmap0, 0, 0, w, h, Stride, Scan0, BitmapData)
;Loop, %h%
;{ 
;  Loop, %w%
;  {
;    ARGB:=NumGet(Scan0+0, y*Stride+(A_Index-1)*4)
;    A := (0xff000000 & ARGB) >> 24
;    R := (0x00ff0000 & ARGB) >> 16
;    G := (0x0000ff00 & ARGB) >> 8
;    B := (0x000000ff & ARGB)
;  }
;}
;Gdip_UnlockBits(pBitmap0, BitmapData)

GuiClose:
Exit:
Gdip_DisposeImage(pBitmap), Gdip_DeleteBrush(pBrush0)
Gdip_DeleteGraphics(G0), Gdip_DisposeImage(pBitmap0), DeleteObject(hBitmap)
Gdip_Shutdown(pToken)
ExitApp

"You annoy me, therefore I exist."

tic
  • Members
  • 1934 posts
  • Last active: Dec 21 2015 01:05 PM
  • Joined: 22 Apr 2007
Very interesting Zaelia. Thanks for posting this

Drugwash
  • Members
  • 1078 posts
  • Last active: May 24 2016 04:20 PM
  • Joined: 07 Sep 2008
Adding AltSubmit property to the Slider will make it work in real-time.
Commenting out DeleteObject(hBitmap) will make it work in 9x too. ;)

(AHK 1.0.48.05 and Win98SE) forever | My scripts are here


Zaelia
  • Members
  • 754 posts
  • Last active: Jan 17 2015 02:38 AM
  • Joined: 31 Oct 2008
I had problems, more and more web page embed picture in base64 in the main source code (but not for IE), and I had difficulties to find (xor understand) information about your BRA file type... So I have a suggestion, for generic usage to get bitmap from a "variable", without break old script:

Gdip_BitmapFromBRA(...)
{
  ... parse (as old version )
  BRA managment
      Gdip_BitmapFromMemory(...)
}

Gdip_BitmapFromMemory(...)
{
  ... create Stream (maybe global, move or copy memory ?)
  DllCall("gdiplus\GdipCreateBitmapFromStream", ...)
  return pbitmap
}

example of use for my problem
#NoEnv
OnExit, Exit
pToken := Gdip_Startup()

StringCaseSense, On
Chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

code:="iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="

Base64Decode(data, code)

;BinWrite("reddot.png", data)
;FileRead, data, *c reddot.png
;pBitmap := Gdip_CreateBitmapFromFile("reddot.png")


Gdip_CreateBitmapFromMemory(data, 3*StrLen(code)//4)


Gdip_GetDimensions(pBitmap, w, h)
Gui, 1: Add, Picture, x0 y0 w%w% h%h% 0xE hwndMyPic
Gui, 1: Show, w%w% h%h% , % "Do you see the red dot ?"

hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
SetImage(MyPic, hBitmap)
DeleteObject(hBitmap)
return


GuiClose:
Exit:
Gdip_DisposeImage(pBitmap), DeleteObject(hBitmap)
Gdip_Shutdown(pToken)
ExitApp


Gdip_CreateBitmapFromMemory(ByRef Buffer, nSize)
{
global
	hData := DllCall("GlobalAlloc", "uint", 2, "uint", nSize)
	pData := DllCall("GlobalLock", "uint", hData)
	DllCall("RtlMoveMemory", "uint", pData, "uint", &Buffer, "uint", nSize)
	DllCall("GlobalUnlock", "uint", hData)
	DllCall("ole32\CreateStreamOnHGlobal", "uint", hData, "int", 1, "uint*", pStream)
	DllCall("gdiplus\GdipCreateBitmapFromStream", "uint", pStream, "uint*", pBitmap)
	DllCall(NumGet(NumGet(1*pStream)+8), "uint", pStream)
}


Base64Decode(ByRef bin, code) { 
   StringReplace code, code, =,,All 
   VarSetCapacity(bin, 3*StrLen(code)//4, 0) 
   Loop Parse, code 
   { 
      m := A_Index & 3 ; mod 4 
      IfEqual m,0, { 
         buffer += DeCode(A_LoopField) 
         Append(bin, pos, buffer>>16, 255 & buffer>>8, 255 & buffer) 
      } 
      Else IfEqual m,1, SetEnv buffer, % DeCode(A_LoopField) << 18 
      Else buffer += DeCode(A_LoopField) << 24-6*m 
   } 
   IfEqual m,0, Return 
   IfEqual m,2 
        Append(bin, pos, buffer>>16) 
   Else Append(bin, pos, buffer>>16, 255 & buffer>>8) 
} 

Append(ByRef bin, ByRef pos, c1, c2="", c3="", c4="") { 
   pos += 0 
   Loop 4 { 
      IfEqual c%A_Index%,, Break 
      DllCall("RtlFillMemory",UInt,&bin+pos, UInt,1, UChar,c%A_Index%) 
      pos++ 
   } 
} 

DeCode(c) { ; c = a char in Chars ==> position [0,63] 
   Global Chars 
   Return InStr(Chars,c,1) - 1 
}

BinWrite(file, ByRef data, n=0, offset=0) 
{ 
   ; Open file for WRITE (0x40..), OPEN_ALWAYS (4): creates only if it does not exists 
   h := DllCall("CreateFile","str",file,"Uint",0x40000000,"Uint",0,"UInt",0,"UInt",4,"Uint",0,"UInt",0) 
   IfEqual h,-1, SetEnv, ErrorLevel, -1 
   IfNotEqual ErrorLevel,0,Return,0 ; couldn't create the file 

   m = 0                            ; seek to offset 
   IfLess offset,0, SetEnv,m,2 
   r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m) 
   IfEqual r,0, SetEnv, ErrorLevel, -3 
   IfNotEqual ErrorLevel,0, { 
      t = %ErrorLevel%              ; save ErrorLevel to be returned 
      DllCall("CloseHandle", "Uint", h) 
      ErrorLevel = %t%              ; return seek error 
      Return 0 
   } 

   m := VarSetCapacity(data)        ; get the capacity ( >= used length ) 
   If (n < 1 or n > m) 
       n := m 
   result := DllCall("WriteFile","UInt",h,"Str",data,"UInt",n,"UInt *",Written,"UInt",0) 
   if (!result or Written < n) 
       ErrorLevel = -3 
   IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel% 

   h := DllCall("CloseHandle", "Uint", h) 
   IfEqual h,-1, SetEnv, ErrorLevel, -2 
   IfNotEqual t,,SetEnv, ErrorLevel, %t%-%ErrorLevel% 

   Return Written 
}

"You annoy me, therefore I exist."

Anon_0xFFFF
  • Members
  • 2 posts
  • Last active: Sep 21 2011 09:30 PM
  • Joined: 21 Sep 2011
Let me start off by saying 'Hi'. I'm new here, as well as new to AHK.

I've installed AHK_L (64bit) on Win7 (64bit) and played around with it a bit; enough to want to start learning something a bit more advanced (GDI+). I've downloaded v1.45 and the first two examples.

Method 1)
Place DrawShapes.ahk in a folder along with gdip.ahk
Uncomment #Include... in DrawShapes.ahk, Save.
Run DrawShapes.ahk
No Joy :(

Method 2)
Place DrawShapes.ahk in a folder
Place gdip.ahk in ../AutoHotKey/Lib/
Comment #Include... in DrawShapes.ahk, Save.
Run DrawShapes.ahk
No Joy :(

After some searching, I turned off Aero - but no change.
After some more searching, I installed AHK_L (32bit) - Success
Turned Aero back on - still works.

So, I guess my question is; Is there a problem with AHK(64bit) or is there something I should be doing to make the examples work with AHK(64bit)?

fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
FYI, I made some time ago a 64-bit compatible version of this library.

Anon_0xFFFF
  • Members
  • 2 posts
  • Last active: Sep 21 2011 09:30 PM
  • Joined: 21 Sep 2011

FYI, I made some time ago a 64-bit compatible version of this library.


Thank you fincs!

capbat
  • Members
  • 191 posts
  • Last active: Feb 08 2017 06:57 PM
  • Joined: 29 Nov 2007
Can this lib be used to create bar charts?

Bat

tic
  • Members
  • 1934 posts
  • Last active: Dec 21 2015 01:05 PM
  • Joined: 22 Apr 2007

Can this lib be used to create bar charts?

Bat


It surely can...(Note that this is a bit sloppy and I'm sure some of the maths is a bit wrong - but it's just an example!)

#SingleInstance, Force
#NoEnv
SetBatchLines, -1

pToken := Gdip_Startup()

barWidth := 80
gapWidth := 40
bars := 3

t := 40
Width := (bars*barWidth)+((bars+1)*gapWidth), Height := Width+t

Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop
Gui, 1: Show, NA
hwnd1 := WinExist()

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

bar_pPenWidth := 5
Loop, %bars%
{
	bar_Height%A_Index% := 0
	Random, rR, 0, 255
	Random, rG, 0, 255
	Random, rB, 0, 255
	dR := (rR-80 < 0) ? 0 : rR-80, dG := (rG-80 < 0) ? 0 : rG-80, dB := (rB-80 < 0) ? 0 : rB-80
	bR := (rR+80 > 255) ? 255 : rR+80, bG := (rG+80 > 255) ? 255 : rG+80, bG := (rG+80 > 255) ? 255 : rG+80
	
	bar_pBrush%A_Index% := Gdip_CreateLineBrushFromRect(0, 0, barWidth, Height-t, Gdip_ToARGB(210, dR, dG, dB), Gdip_ToARGB(120, rR, rG, rB))
	bar_pPen%A_Index% := Gdip_CreatePen(Gdip_ToARGB(15, rR, rG, rB), bar_pPenWidth)
}

pBrushBack := Gdip_BrushCreateSolid(Gdip_ToARGB(15, 20, 20, 20))
pPenBlack := Gdip_CreatePen(0x77000000, pPenBlackWidth := 10)

Options = x100 y100 w%barWidth% Centre cee000000 r4 s20 Bold
RC := Gdip_TextToGraphics(G, "999", Options, "Arial", Width, Height, 1)
StringSplit, RC, RC, |

UpdateLayeredWindow(hwnd1, hdc, (A_ScreenWidth-Width)//2, (A_ScreenHeight-Height)//2, Width, Height)
SetTimer, Update, 30
return

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

Update:
Gdip_GraphicsClear(G)
Gdip_FillRectangle(G, pBrushBack, 0, 0, Width, Height)
Loop, %bars%
{
	bar_Height%A_Index% += 2*A_Index
	
	if (Round(100*(bar_Height%A_Index%/(Height))) > 100)
		bar_Height%A_Index% -= Rand
	
	x := (A_Index*gapWidth)+((A_Index-1)*barWidth)
	y := Height-bar_Height%A_Index%
	h := bar_Height%A_Index%-pPenBlackWidth
	p := Round(100*(bar_Height%A_Index%/(Height-t)))
	
	Gdip_FillRectangle(G, bar_pBrush%A_Index%, x, y, barWidth, h)
	Gdip_DrawLines(G, bar_pPen%A_Index%, x+(bar_pPenWidth//2) "," Height-(bar_pPenWidth//2)-pPenBlackWidth "|"  x+(bar_pPenWidth//2) "," y+(bar_pPenWidth//2) "|" x+barWidth "," y+(bar_pPenWidth//2))
	
	y -= RC4
	Options = x%x% y%y% w%barWidth% Centre cee000000 r4 s20 Bold
	Gdip_TextToGraphics(G, p "%", Options, "Arial", Width, Height)
	
	if (p >= 100)
		SetTimer, Update, Off
}
Gdip_DrawLines(G, pPenBlack,  pPenBlackWidth//2 ",0|"  pPenBlackWidth//2 "," Height-(pPenBlackWidth//2) "|" Width "," Height-(pPenBlackWidth//2))
UpdateLayeredWindow(hwnd1, hdc)
return

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

Esc::
Gdip_DeleteBrush(pBrushBack), Gdip_DeleteBrush(pPenBlack)
Loop, %bars%
{
	Gdip_DeleteBrush(bar_pBrush%A_Index%)
	Gdip_DeletePen(bar_pPen%A_Index%)
}
SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc), Gdip_DeleteGraphics(G)
Gdip_Shutdown(pToken)
Gdip_Shutdown(pToken)
ExitApp
return

ps. If I were to do this properly I would use machine code to make it look nicer

Daeger
  • Members
  • 66 posts
  • Last active: Feb 29 2012 10:37 PM
  • Joined: 18 May 2009

FYI, I made some time ago a 64-bit compatible version of this library.


Hey fincs, I sent you a PM about it, but just in case you don't see it since PMs seem easy to miss, I'm interested in getting a 64-bit version of the GDip_ImageSearch function posted here: <!-- m -->http://www.autohotke... ... 919#470919<!-- m -->

nimda
  • Members
  • 4368 posts
  • Last active: Aug 09 2015 02:36 AM
  • Joined: 26 Dec 2010
Tic, I have this question: "What is a DC, and why do we select stuff into it all the time? What is 'selecting'?"

Where can I learn what is happening, instead of just copypasting the GDI+ tutorials into my scripts?

Daeger
  • Members
  • 66 posts
  • Last active: Feb 29 2012 10:37 PM
  • Joined: 18 May 2009
Okay, so, GetPixelColor is slow on Windows Vista/7 due to Aero, and unless you want to disable it, it's going to be slow, so I thought I'd look up alternatives because I'm really starting to hate the Windows Basic interface.

I came across the GDI+ Library, but not being a very advanced user, I asked for help in beginning to use it, and thanks to a couple good people, I got its PixelGet function working how I need it to.

The only problem is.. it's very slightly slower than PixelGetColor, I figured out how to benchmark it. I'm guessing this is due to it capturing the screen every time I hit the button, but it kind of HAS to do that to suit my purposes.

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#Include Gdip.ahk
pToken := GDIP_StartUp()

F1::
pBitMap := GDIP_BitmapFromScreen()
color := "0x644E37"
ARGB := GDIP_GetPixel(pbitmap, "0", "0")
If (ARGBtoRGB(ARGB) == color)
{
   MsgBox Detected!
}
Else
{
   MsgBox Not Detected.
}
Gdip_DisposeImage(pBitmap)
return

ARGBtoRGB( ARGB )
    {
        VarSetCapacity( RGB,6,0 )
        DllCall( "msvcrt.dll\sprintf", Str,RGB, Str,"%06X", UInt,ARGB<<8 )
        Return "0x" RGB
    }

If there's anything I can do with my code to speed it up, that'd be great. Maybe somehow getting BitmapFromScreen to only capture that one specific pixel on the screen?

I also read something about compiling to machine code but I didn't know what to make of it.

Drugwash
  • Members
  • 1078 posts
  • Last active: May 24 2016 04:20 PM
  • Joined: 07 Sep 2008
Some generic directives added at the top, may help:
SetWinDelay, -1
SetControlDelay, -1
SetBatchLines, -1
ListLines, Off
For GDI+ specific tips I'll let others more knowledgeable chime in.

(AHK 1.0.48.05 and Win98SE) forever | My scripts are here


Daeger
  • Members
  • 66 posts
  • Last active: Feb 29 2012 10:37 PM
  • Joined: 18 May 2009

Some generic directives added at the top, may help:

SetWinDelay, -1
SetControlDelay, -1
SetBatchLines, -1
ListLines, Off
For GDI+ specific tips I'll let others more knowledgeable chime in.


Oh, cool - yes, that did speed it up quite a bit, I went from ~47ms for the command down to 6. Still nowhere near as fast as PixelGetColor with Aero disabled though, but definitely a huge improvement.

Still, I'm curious if there's more I can do, I'm sure capturing a smaller section of the screen would help and I'm honestly curious about how compiling it is supposed to work.

Daeger
  • Members
  • 66 posts
  • Last active: Feb 29 2012 10:37 PM
  • Joined: 18 May 2009
Actually, it looks like having Aero on slows down Gdip_BitmapFromScreen() quite a bit too, so PixelGetColor is still faster with those options.