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
guest3456
  • Guests
  • Last active:
  • Joined: --
ok so i found a website claiming that LockBits is so superior to normal GDI GetPixel

speed and effeciency is of utmost importance to me so i ran some tests using GDIP library. previously ive just been using GDI GetPixel

according to my tests, both GDIP methods are slower than normal GetPixel. maybe i'm doing things wrong?

heres my code, mouseover a window and press f3

OnExit, ExitSub
#include gdip.ahk

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

return   ;// end of autoexec



f3::
   tooltip, scanning pixels - please wait
   MouseGetPos,,, win
   
   loops := 10
   
   xx := 40
   yy := 50
   
   ;// AHK PixelGetColor
   PGCstartTime := A_TickCount
   Loop, %loops%
   {
      WinActivate, ahk_id %win%
      PixelGetColor, PGCcolor, xx, yy
   }
   PGCtime := A_TickCount-PGCstartTime
   
   ;// GDI GetPixel
   PCAStartTime := A_TickCount
   Loop, %loops%
   {
      PCAcolor := GetPixel(xx, yy, win)
   }
   PCAtime := A_TickCount-PCAStartTime
   
   ;// Gdip_GetPixel
   GDIPGPstartTime := A_TickCount
   Loop, %loops%
   {
      GDIPGPcolor := GdipGetPixel(xx, yy, win)
   }
   GDIPGPtime := A_TickCount - GDIPGPstartTime
   
   ;// Gdip_LockBits
   GDIPLstartTime := A_TickCount
   Loop, %loops%
   {
      GDIPLcolor := GetLockBitPixel(xx, yy, win)
   }
   GDIPLtime := A_TickCount - GDIPLstartTime
   
   tooltip,
      
   msgboxstr := "AHK PixelGetColor`n" . PGCcolor . "`nfound " . loops . " times in " . PGCtime . "ms`n`n"
   msgboxstr .= "GDI GetPixel`n" . PCAcolor . "`nfound " . loops . " times in " . PCAtime . "ms`n`n"
   msgboxstr .= "Gdip GetPixel`n" . GDIPGPcolor . "`nfound " . loops . " times in " . GDIPGPtime . "ms`n`n"
   msgboxstr .= "Gdip GetLockBitPixel`n" . GDIPLcolor . "`nfound " . loops . " times in " . GDIPLtime . "ms"
   msgbox, %msgboxstr%
   

   
return



ExitSub:
   Gdip_Shutdown(pToken)
   ExitApp
return





GetPixel(col_x,col_y,id)
{
   pix := ""
   
   WinGetPos, , , w, h, ahk_id %id%
   hDC := DllCall("GetDC", "UInt", id)
   hCDC := DllCall("gdi32.dll\CreateCompatibleDC", "UInt", hDC)
   hBMP := DllCall("gdi32.dll\CreateCompatibleBitmap", "UInt", hDC, "Int", w, "Int", h)
   hOldObj := DllCall("gdi32.dll\SelectObject", "UInt", hCDC, "UInt", hBMP)
   
   DllCall("PrintWindow", "UInt", id, "UInt", hCDC, "UInt", 0)
   DllCall("RedrawWindow", "UInt", id, "UInt", 0, "UInt", 0, "UInt", 1|16|32|64|1024)
  
   pix := DllCall("GetPixel", "UInt", hCDC, "Int", col_x, "Int", col_y)
   
   oldfrmt := A_FormatInteger
   SetFormat, IntegerFast, hex
   pix += 0
   pix .= ""
   SetFormat, IntegerFast, %oldfrmt%   
   
   DllCall("gdi32.dll\SelectObject", "UInt", hCDC, "UInt", hOldObj)
   DllCall("gdi32.dll\ReleaseDC", "UInt", id, "UInt", hDC)
   DllCall("gdi32.dll\DeleteObject", "UInt", hBMP)      
   DllCall("gdi32.dll\DeleteDC", "UInt", hCDC)
   DllCall("gdi32.dll\DeleteDC", "UInt", hDC)
   
   return pix
}




GetLockBitPixel(x,y,id)
{
   if (!pBitmap := Gdip_BitmapFromHWND(id))
   {
      MsgBox, 48, error getting bitmap
      ExitApp
   }
   Width1 := Gdip_GetImageWidth(pBitmap)
   Height1 := Gdip_GetImageHeight(pBitmap)
   Gdip_LockBits(pBitmap, 0, 0, Width1, Height1, Stride1, Scan1, BitmapData1)
   
   GDIPcolor := Gdip_GetLockBitPixel(Scan1, x, y, Stride1)
   ;Gdip_FromARGB(Gdip_GetLockBitPixel(Scan1, x, y, Stride1), a, r, g, b)
   ;GDIPcolor := r . g . b
   
   oldfrmt := A_FormatInteger
   SetFormat, IntegerFast, hex
   GDIPcolor += 0
   GDIPcolor .= ""
   SetFormat, IntegerFast, %oldfrmt%   

   Gdip_UnlockBits(pBitmap, BitmapData1)
   Gdip_DisposeImage(pBitmap)
   return GDIPcolor
}




GdipGetPixel(x, y, id)
{
   if (!pBitmap := Gdip_BitmapFromHWND(id))
   {
      MsgBox, 48, error getting bitmap
      ExitApp
   }
   
   GDIPcolor := Gdip_GetPixel(pBitmap, x, y)
   ;Gdip_FromARGB(Gdip_GetPixel(pBitmap, x, y), a, r, g, b)
   ;GDIPcolor := r . g . b
   
   oldfrmt := A_FormatInteger
   SetFormat, IntegerFast, hex
   GDIPcolor += 0
   GDIPcolor .= ""
   SetFormat, IntegerFast, %oldfrmt%   

   Gdip_DisposeImage(pBitmap)
   return GDIPcolor
}


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

ok so i found a website claiming that LockBits is so superior to normal GDI GetPixel

speed and effeciency is of utmost importance to me so i ran some tests using GDIP library. previously ive just been using GDI GetPixel

according to my tests, both GDIP methods are slower than normal GetPixel. maybe i'm doing things wrong?

heres my code, mouseover a window and press f3

OnExit, ExitSub
#include gdip.ahk

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

return   ;// end of autoexec



f3::
   tooltip, scanning pixels - please wait
   MouseGetPos,,, win
   
   loops := 10
   
   xx := 40
   yy := 50
   
   ;// AHK PixelGetColor
   PGCstartTime := A_TickCount
   Loop, %loops%
   {
      WinActivate, ahk_id %win%
      PixelGetColor, PGCcolor, xx, yy
   }
   PGCtime := A_TickCount-PGCstartTime
   
   ;// GDI GetPixel
   PCAStartTime := A_TickCount
   Loop, %loops%
   {
      PCAcolor := GetPixel(xx, yy, win)
   }
   PCAtime := A_TickCount-PCAStartTime
   
   ;// Gdip_GetPixel
   GDIPGPstartTime := A_TickCount
   Loop, %loops%
   {
      GDIPGPcolor := GdipGetPixel(xx, yy, win)
   }
   GDIPGPtime := A_TickCount - GDIPGPstartTime
   
   ;// Gdip_LockBits
   GDIPLstartTime := A_TickCount
   Loop, %loops%
   {
      GDIPLcolor := GetLockBitPixel(xx, yy, win)
   }
   GDIPLtime := A_TickCount - GDIPLstartTime
   
   tooltip,
      
   msgboxstr := "AHK PixelGetColor`n" . PGCcolor . "`nfound " . loops . " times in " . PGCtime . "ms`n`n"
   msgboxstr .= "GDI GetPixel`n" . PCAcolor . "`nfound " . loops . " times in " . PCAtime . "ms`n`n"
   msgboxstr .= "Gdip GetPixel`n" . GDIPGPcolor . "`nfound " . loops . " times in " . GDIPGPtime . "ms`n`n"
   msgboxstr .= "Gdip GetLockBitPixel`n" . GDIPLcolor . "`nfound " . loops . " times in " . GDIPLtime . "ms"
   msgbox, %msgboxstr%
   

   
return



ExitSub:
   Gdip_Shutdown(pToken)
   ExitApp
return





GetPixel(col_x,col_y,id)
{
   pix := ""
   
   WinGetPos, , , w, h, ahk_id %id%
   hDC := DllCall("GetDC", "UInt", id)
   hCDC := DllCall("gdi32.dll\CreateCompatibleDC", "UInt", hDC)
   hBMP := DllCall("gdi32.dll\CreateCompatibleBitmap", "UInt", hDC, "Int", w, "Int", h)
   hOldObj := DllCall("gdi32.dll\SelectObject", "UInt", hCDC, "UInt", hBMP)
   
   DllCall("PrintWindow", "UInt", id, "UInt", hCDC, "UInt", 0)
   DllCall("RedrawWindow", "UInt", id, "UInt", 0, "UInt", 0, "UInt", 1|16|32|64|1024)
  
   pix := DllCall("GetPixel", "UInt", hCDC, "Int", col_x, "Int", col_y)
   
   oldfrmt := A_FormatInteger
   SetFormat, IntegerFast, hex
   pix += 0
   pix .= ""
   SetFormat, IntegerFast, %oldfrmt%   
   
   DllCall("gdi32.dll\SelectObject", "UInt", hCDC, "UInt", hOldObj)
   DllCall("gdi32.dll\ReleaseDC", "UInt", id, "UInt", hDC)
   DllCall("gdi32.dll\DeleteObject", "UInt", hBMP)      
   DllCall("gdi32.dll\DeleteDC", "UInt", hCDC)
   DllCall("gdi32.dll\DeleteDC", "UInt", hDC)
   
   return pix
}




GetLockBitPixel(x,y,id)
{
   if (!pBitmap := Gdip_BitmapFromHWND(id))
   {
      MsgBox, 48, error getting bitmap
      ExitApp
   }
   Width1 := Gdip_GetImageWidth(pBitmap)
   Height1 := Gdip_GetImageHeight(pBitmap)
   Gdip_LockBits(pBitmap, 0, 0, Width1, Height1, Stride1, Scan1, BitmapData1)
   
   GDIPcolor := Gdip_GetLockBitPixel(Scan1, x, y, Stride1)
   ;Gdip_FromARGB(Gdip_GetLockBitPixel(Scan1, x, y, Stride1), a, r, g, b)
   ;GDIPcolor := r . g . b
   
   oldfrmt := A_FormatInteger
   SetFormat, IntegerFast, hex
   GDIPcolor += 0
   GDIPcolor .= ""
   SetFormat, IntegerFast, %oldfrmt%   

   Gdip_UnlockBits(pBitmap, BitmapData1)
   Gdip_DisposeImage(pBitmap)
   return GDIPcolor
}




GdipGetPixel(x, y, id)
{
   if (!pBitmap := Gdip_BitmapFromHWND(id))
   {
      MsgBox, 48, error getting bitmap
      ExitApp
   }
   
   GDIPcolor := Gdip_GetPixel(pBitmap, x, y)
   ;Gdip_FromARGB(Gdip_GetPixel(pBitmap, x, y), a, r, g, b)
   ;GDIPcolor := r . g . b
   
   oldfrmt := A_FormatInteger
   SetFormat, IntegerFast, hex
   GDIPcolor += 0
   GDIPcolor .= ""
   SetFormat, IntegerFast, %oldfrmt%   

   Gdip_DisposeImage(pBitmap)
   return GDIPcolor
}


Hehe....yeh you are using it incorrectly :)

Using lockbits is only faster if you intend on doing more than one operation. So every time you are calling your function GetLockBitPixel you are:

getting the bitmap
getting the dimensions
locking the bits
using Gdip_GetLockBitPixel to get the ARGB

to make full use of this you need to only do the top 3 steps once and then the last over and over again

Note though that if you really need speed then whilst locking the bits and using ahk to get the ARGB will be 100s of times faster.....if speed is really important then you will need to call a dll or machine code as that will be 1000s of times faster

Edit:

Also as a note I've just had a quite scan through that link you posted and I wouldnt follow that guy. He doesnt seem to quite understand some things...ie:

void SetColor(Color color)
{
   _current[0]= color.R;
   _current [1] = color.G;
   _current [2] = color.B;
}

Not only is this a very sloppy way of coding, but also incorrect. gdi+ stores info in BGRA format not ARGB, so the order should be reversed as Ive shown previously in c++...

void MyFunc(unsigned char * Scan0, int w, int h, int Stride)
{
	int o, A, R, G, B;
	for (int y = 0; y < h; ++y)
	{
		for (int x = 0; x < w; ++x)
		{
			o = (4*x)+(y*Stride);
			A = Scan0[3+o];
			R = Scan0[2+o];
			G = Scan0[1+o];
			B = Scan0[o];
			// Do whatever here...
		}
	}
}


le-mec
  • Members
  • 51 posts
  • Last active: Dec 15 2011 02:30 AM
  • Joined: 24 Dec 2006
I'm trying to create a sort of "mouse trail" with GDI+ but I think I'm going about things the wrong way.

I created a drawing context that is the size of the entire screen (lol, I bet you can see where this is headed...) and have been using the following update routine to benchmark it with a SetTimer thread running at 1ms intervals:

Random, px, 0, 1280
Random, py, 0, 800
Random, qx, 0, 1280
Random, qy, 0, 800
Gdip_DrawLine(mtrail_G, nPen,px,py,qx,qy)
; UpdateLayeredWindow(mtrail_hWnd, mtrail_hdc,"","","","")

As expected, my quad-core PC normally meant for high-end graphics work got somewhat pokey so the route of trying to update THE WHOOOLE SCREEN is a definite no-no.

Anyways, what I'm trying to do is have the cursor leave a 1px-wide line trail that slowly fades away over time.

I'm using it as a drawing aid with a wacom tablet which would allow me to "air-sketch" by moving the stylus around without actually applying any pen pressure and have a continually fading airsketch drawing superimposed over my actual drawing software.

It's a difficult task since the drawing has to fade away over time and the pen could really wind up anywhere on screen at any time, meaning that the trail could be anywhere. I've considered dicing up the screen into bits and fading the individual buckets with idle time, but that sounds somewhat inelegant.

So the problem is:

How should we deal with a fullscreen drawing context that must be faded at a high frame rate, even though "new ink" is only being introduced in a small portion of the screen at any given time?

In an ideal world where all my coding problems could be solved easily and I could gain super-strength by eating ordinary packets of ramen, there would be a function that can fade an entire drawing context quickly and "destructively", and maybe some way to refresh a small portion of the drawing context (rather than the whole kit kaboodle).

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

Come on little guy :wink: have a little ingenuity

Here's a simple idea to have it run perfectly fast (for ahk) without having to rewrite the code:

#SingleInstance, Force
DetectHiddenWindows, On
#NoEnv
SetBatchLines, -1
Coordmode, Pixel, Screen
Coordmode, Mouse, Screen

AppName = Desktop.Painter
VersionNum = 1.02

ColourN = Red|Green|Blue
ColourH = ffff0000|ff00ff00|ff0000ff
StringSplit, ColourN, ColourN, |
StringSplit, ColourH, ColourH, |

SW := 50
BackColour := 0xff475155

#Include, Gdip.ahk

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

Menu, Tray, NoStandard
Menu, Tray, DeleteAll
Menu, Tray, Add, Toggle Notes, ToggleNotes
Menu, Tray, Add, Exit, Exit
Menu, Tray, Default, Toggle Notes

SysGet, MonitorPrimary, MonitorPrimary
SysGet, WA, MonitorWorkArea, %MonitorPrimary%
WAWidth := WARight-WALeft, WAHeight := WABottom-WATop

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

Gui, 2: -Caption +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs +Owner1
hwnd2 := WinExist()
Gui, 2: Color, 475155

Gui, 2: Add, Button, x135 y10 w50 gSave Default, &Save...
Loop, %ColourN0%
{
	Gui, 2: Add, Picture, % ((A_Index = 1) ? "x15 y+10" : "x+10 yp+0") " w" SW " h" SW " gChangeColour 0xE v" ColourH%A_Index% " hwnd" ColourN%A_Index%
	
	pBrush := Gdip_BrushCreateSolid("0x" ColourH%A_Index%)
	pBitmap := Gdip_CreateBitmap(SW, SW), G := Gdip_GraphicsFromImage(pBitmap)
	Gdip_FillRectangle(G, pBrush, 0, 0, SW, SW)
	hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
	hwnd := ColourN%A_Index%, SetImage(%hwnd%, hBitmap)
	
	Gdip_DeleteBrush(pBrush), Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), DeleteObject(hBitmap)
}
Gui, 2: Add, Picture, % "x75 y+30 w" SW " h" SW " 0xE hwndPreview"		;%
Gui, 2: Add, Slider, x10 y+40 w180 vPenWidth Tooltip Range1-30 gUpdatePreview, 12
ChosenColour := 0xffff0000
GoSub, UpdatePreview

Gui, 2: Show, w200 h250 x20 y20 NA Hide

pBitmapDraw := Gdip_CreateBitmap(WAWidth, WAHeight), GDrawplus := Gdip_GraphicsFromImage(pBitmapDraw)
Gdip_SetSmoothingMode(GDrawplus, 4)

hbmDraw := CreateDIBSection(WAWidth, WAHeight), hdcDraw := CreateCompatibleDC(), obmDraw := SelectObject(hdcDraw, hbmDraw), GDraw := Gdip_GraphicsFromHDC(hdcDraw)
Gdip_SetSmoothingMode(GDraw, 4)

pBrush := Gdip_BrushCreateSolid(0x01ffffff)
Gdip_FillRectangle(GDrawplus, pBrush, 0, 0, WAWidth, WAHeight), Gdip_FillRectangle(GDraw, pBrush, 0, 0, WAWidth, WAHeight)
Gdip_DeleteBrush(pBrush)

UpdateLayeredWindow(hwnd1, hdcDraw, WALeft, WATop, WAWidth, WAHeight)
Return

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

Save:
Gui, 2: +OwnDialogs
FileSelectFolder, OutFolder,,, Select where you would like to save the image
If !OutFolder
Return
Gdip_SaveBitmapToFile(pBitmapDraw, OutFolder "" A_Now ".png")
Return

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

UpdatePreview:
Gui, 2: Submit, NoHide

pBrush := Gdip_BrushCreateSolid(ChosenColour)
pBrushBack := Gdip_BrushCreateSolid(BackColour)
pBitmap := Gdip_CreateBitmap(SW, SW), G := Gdip_GraphicsFromImage(pBitmap), Gdip_SetSmoothingMode(G, 4)
Gdip_FillRectangle(G, pBrushBack, -2, -2, SW+4, SW+4)
Gdip_FillEllipse(G, pBrush, (SW-PenWidth)//2, (SW-PenWidth)//2, PenWidth, PenWidth)
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
SetImage(Preview, hBitmap)

Gdip_DeleteBrush(pBrushDraw), Gdip_DeletePen(pPenDraw)
pBrushDraw := Gdip_BrushCreateSolid(ChosenColour), pPenDraw := Gdip_CreatePen(ChosenColour, PenWidth)

Gdip_DeleteBrush(pBrush), Gdip_DeleteBrush(pBrushBack), Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap), DeleteObject(hBitmap)
Return

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

ChangeColour:
ChosenColour := "0x" A_GuiControl
GoSub, UpdatePreview
Return

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

WM_LBUTTONDOWN()
{
	Global

	If (A_Gui != 2)
	Return, -1	
	PostMessage, 0xA1, 2
	Drag := 1
}

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

ToggleNotes:
v := IsWindowVisible(hwnd1) || IsWindowVisible(hwnd2)
Gui, % "2: " (v ? "Hide" : "Show")			;%
Gui, % "1: " (v ? "Hide" : "Show")			;%
SetTimer, CheckPos, % (v ? "Off" : 40)		;%
Return

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

CheckPos:
Critical
MouseGetPos, x, y, Win
OnMessage(0x201, (Win = hwnd2) ? "WM_LBUTTONDOWN" : "")
If !GetKeyState("LButton", "P")
Drag := 0
If (Win != hwnd1) || !GetKeyState("LButton", "P") || Drag
{
	Ox := Oy := ""
	Return
}
SetTimer, DelayedSave, Off

Gdip_FillEllipse(GDraw, pBrushDraw, x-(PenWidth//2), y-(PenWidth//2), PenWidth, PenWidth)
Gdip_DrawLine(GDraw, pPenDraw, Ox ? Ox : x, Oy ? Oy : y, x, y)
UpdateLayeredWindow(hwnd1, hdcDraw, WALeft, WATop, WAWidth, WAHeight)

Array .= x "," y "," Ox "," Oy "|"
SetTimer, DelayedSave, -300
Ox := x, Oy := y
Return

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

DelayedSave:
Critical
Loop, Parse, Array, |
{
	StringSplit, c, A_LoopField, `,
	Gdip_FillEllipse(GDrawplus, pBrushDraw, c1-(PenWidth//2), c2-(PenWidth//2), PenWidth, PenWidth)
	Gdip_DrawLine(GDrawplus, pPenDraw, c3 ? c3 : c1, c4 ? c4 : c2, c1, c2)
}
Array := ""
Return

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

IsWindowVisible(hwnd)
{
	Return, DllCall("IsWindowVisible", "UInt", hwnd)
}

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

Exit:
Gdip_DeleteBrush(pBrushDraw), Gdip_DeletePen(pPenDraw)
Gdip_DeleteGraphics(GDrawplus), Gdip_DisposeImage(pBitmapDraw)
Gdip_DeleteGraphics(GDraw), SelectObject(hdcDraw, obmDraw), DeleteObject(hbmDraw), DeleteDC(hdcDraw)
Gdip_Shutdown(pToken)
ExitApp
Return

I slowed the timer to save some cpu

It would also be nice to use GetSaveFileName rather than that button, but that isnt within the scope of me just mucking around :)


Ive quoted myself from near the beginning of this thread...see if this program helps a little...

Unfortunately gdi+ is very resource hungry as it is all computed on the cpu without real hardware acceleration. It would be nice to use something like Direct2D but this doesnt work on xp, which I see as a major limitation :?

le-mec
  • Members
  • 51 posts
  • Last active: Dec 15 2011 02:30 AM
  • Joined: 24 Dec 2006
Hmm, yeah this example ran about as fast as mine did - it's just a limitation of not being able to make use of direct2D.

I am running Win7x64, so I'll try and see if I can find a direct2D equivalent, wish me luck!

Thanks again!

EDIT:

Found a little proof of concept. I will tinker with this for a little while.

guest3456
  • Guests
  • Last active:
  • Joined: --

Hehe....yeh you are using it incorrectly :)

Using lockbits is only faster if you intend on doing more than one operation. So every time you are calling your function GetLockBitPixel you are:

getting the bitmap
getting the dimensions
locking the bits
using Gdip_GetLockBitPixel to get the ARGB


yes thats true, but for the normal gdi GetPixel method, i'm doing the same, creating a bitmap, printwindow'ing the bitmap, getting dimensions, getting the pixel.

and interestingly enough, even the GDI+ GetPixel method is slower (at least on my tests) than the normal gdi calls

so i guess the conclusion is, if i need to grab a bunch of pixels at one time, then lockbits will be faster. i'll probably run some benchmarks on this soon as well and post results

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
Well if you look back through the last few pages you can see the lockbits methods with machine code I have posted.....even try example 12 in the 1st post.....it is several 1000 times faster than the equivalent set/getpixel

Also yeh he doesnt use the stride in his calculations on that link you posted so not only will the ARGB be reversed with his code, but also skewed with any bitmap that doesnt have a width exactly divisible by 3 (for RGB) :wink:

le-mec
  • Members
  • 51 posts
  • Last active: Dec 15 2011 02:30 AM
  • Joined: 24 Dec 2006
I'm still in the running with this tracing paper script! I know it's possible to get a Bitmap from a screengrab with Gdip_GetBitmapFromScreen -- but would it be possible to get a bitmap from a "Graphics" object? I'm trying to apply an incremental alpha fade on every refresh.

[*:31gfi0xb]EDIT: I'm gonna try using Gdip_BitmapFromHWND
[*:31gfi0xb]EDIT2: nope! didn't work! it won't grab a transparent image, also it strobes :D
I tried adding this function, but I don't think I got it right.
Gdip_CreateBitmapFromGraphics(Width, Height, pGraphics)
{
    DllCall("gdiplus\GdipCreateBitmapFromGraphics", "int", Width, "int", Height, "uint", pGraphics, "uint*", pBitmap)
    Return pBitmap
}
I got it from the MSDN reference

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
Nothing mentioned on that page will help you unfortunately. its all common sense for the most part or is already built into my gdi+ library.

All bitmaps created are by default ARGB and all the reset are pretty much set by default (although they dont make a big difference in previous testing)

I guess the fastest way would be using gdi with ppvBits:

CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0)

and next fastest would be compiling a dll with your own custom drawing functions with LockBits, which would allow more flexibility that the 1st method

Heh...and as that guy said in his article...multithreading doesnt work :wink:

<!-- m -->http://social.msdn.m... ... 733c2f22fc<!-- m -->

le-mec
  • Members
  • 51 posts
  • Last active: Dec 15 2011 02:30 AM
  • Joined: 24 Dec 2006

Nothing mentioned on that page will help you unfortunately. its all common sense for the most part or is already built into my gdi+ library.

All bitmaps created are by default ARGB and all the reset are pretty much set by default (although they dont make a big difference in previous testing)

I guess the fastest way would be using gdi with ppvBits:

CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0)

and next fastest would be compiling a dll with your own custom drawing functions with LockBits, which would allow more flexibility that the 1st method


I used the wrong tinyURL link. It should be this one: <!-- m -->http://tinyurl.com/2fjlwl3<!-- m -->

le-mec
  • Members
  • 51 posts
  • Last active: Dec 15 2011 02:30 AM
  • Joined: 24 Dec 2006
What I need to do is create something similar to Gdip_GraphicsClear, except it doesn't just blow everything away in one step, but rather subtracts a proportion of the alpha from all of the pixels so that it can be used to apply an overall fade in increments. I would prefer not to have to perform bitmap operations if it could be avoided, but...

So far, most of the functions allow for overlaying images overtop of one another so that gradually you get a result that gets more and more opaque, but when it comes to erasing, it's all or nothing. :p

tic
  • Members
  • 1934 posts
  • Last active: May 30 2018 08:13 PM
  • Joined: 22 Apr 2007
You have 2 easy methods to make the entire window more transparent:

UpdateLayeredWindow(hwnd, hdc, x="", y="", w="", h="", [color=red]Alpha[/color]=255)

; Matrix betwen 0 and 1 for opacity
Gdip_DrawImage(pGraphics, pBitmap, dx="", dy="", dw="", dh="", sx="", sy="", sw="", sh="", [color=red]Matrix[/color]=1)


le-mec
  • Members
  • 51 posts
  • Last active: Dec 15 2011 02:30 AM
  • Joined: 24 Dec 2006
I'm trying to have a drawing canvas that is completely transparent except for the lines that are being drawn, but the lines must progressively fade away. I am not looking to have a constant semitransparency.

Here's what I have so far, er, try to imagine the black background being transparent.

Escape key exits, CTRL+S reloads (for testing purposes)
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#Persistent
#SingleInstance force

SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

CoordMode Mouse, Screen
CoordMode Pixel, Screen
SetBatchLines , -1

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

GNum++
Gui, %GNum%: -Resize -Caption +E0x80000 +E0x20 +LastFound +AlwaysOnTop +ToolWindow +OwnmDialogs
Gui, %GNum%: Show, NA
ptrail_hWnd := WinExist()

ptrail_width := 300
ptrail_height := 300
ptrail_hbm := CreateDIBSection(ptrail_width, ptrail_height), ptrail_hdc := CreateCompatibleDC()
ptrail_obm := SelectObject(ptrail_hdc, ptrail_hbm), ptrail_G := Gdip_GraphicsFromHDC(ptrail_hdc)

UpdateLayeredWindow(ptrail_hWnd, ptrail_hdc, 40, 40, ptrail_width, ptrail_height)

SetTimer, Fade, 40

Return

~^s::
	tooltip RELOADING
	if (GDILoaded)
		Gdip_Shutdown(pToken)
	
	Reload
	ExitApp
Return

~*Escape::
	tooltip EXITING
	if (GDILoaded)
		Gdip_Shutdown(pToken)
	ExitApp
Return

Fade:
	; fade the drawing
	Matrix =

	( LTrim Join
		1|0|0|0|0|
		0|1|0|0|0|
		0|0|1|0|0|
		0|0|0|0.99|0|
		0|0|0|0|1
	)
	pTrail_bitmap := Gdip_CreateBitmapFromHBITMAP(ptrail_hbm)
	Gdip_GraphicsClear(ptrail_G)
	Gdip_DrawImage(ptrail_G, pTrail_bitmap,"","","","","","","","",Matrix)
	Gdip_DisposeImage(pTrail_bitmap)

	; add a new line
	Random, r1, 0, %ptrail_width%
	Random, r2, 0, %ptrail_height%
	Random, r3, 0, %ptrail_width%
	Random, r4, 0, %ptrail_height%

	nBaseColor  := 0x007fff
	nPen:=Gdip_CreatePen(((255)<<24)+nBaseColor, 1)
	Gdip_DrawLine(ptrail_G, nPen,r1,r2,r3,r4)
	Gdip_DeletePen(nPen)
	UpdateLayeredWindow(ptrail_hWnd, ptrail_hdc)
Return


le-mec
  • Members
  • 51 posts
  • Last active: Dec 15 2011 02:30 AM
  • Joined: 24 Dec 2006
The problem is that Gdip_CreateBitmapFromHBITMAP does not care about alpha.

SetColorKey seems to hold some promise since I could set it so that black would be the fully transparent start of the range, and that blue could be the fully opaque end of the transparency range. It is late and I am too pooped to go on for now.

<!-- m -->http://msdn.microsof.../ms535429(VS.85<!-- m -->).aspx

le-mec
  • Members
  • 51 posts
  • Last active: Dec 15 2011 02:30 AM
  • Joined: 24 Dec 2006
I GOT IT!!!! YES! The Matrix is all powerful.

Paper Trail:
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#Persistent
#SingleInstance force

SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

CoordMode Mouse, Screen
CoordMode Pixel, Screen
SetBatchLines , -1

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

GNum++
Gui, %GNum%: -Resize -Caption +E0x80000 +E0x20 +LastFound +AlwaysOnTop +ToolWindow +OwnmDialogs
Gui, %GNum%: Show, NA
ptrail_hWnd := WinExist()

ptrail_width := 300
ptrail_height := 300
ptrail_hbm := CreateDIBSection(ptrail_width, ptrail_height), ptrail_hdc := CreateCompatibleDC()
ptrail_obm := SelectObject(ptrail_hdc, ptrail_hbm), ptrail_G := Gdip_GraphicsFromHDC(ptrail_hdc)

; Gdip_SetCompositingMode(ptrail_G, 0)

ptrail_ofsX := 0
ptrail_ofsY := 0

UpdateLayeredWindow(ptrail_hWnd, ptrail_hdc, ptrail_ofsX, ptrail_ofsY, ptrail_width, ptrail_height)

SetTimer, AddLines, 1 ; the faster this one is, the more lines are added between fades
SetTimer, Fade, 100 ; the faster this one is, the smaller the groups of lines are faded out
SetTimer, updateimage, 40 ; the faster this one is, the more frequently the image is updated

Return

~^s::
	tooltip RELOADING
	if (GDILoaded)
		Gdip_Shutdown(pToken)
	
	Reload
	ExitApp
Return

~*Escape::
	tooltip EXITING
	if (GDILoaded)
		Gdip_Shutdown(pToken)
	ExitApp
Return

AddLines:
	; auto scrolling
	MouseGetPos,x,y
	oldOfsX := ptrail_ofsX
	oldOfsY := ptrail_ofsY
	ptrail_ofsX := x < ptrail_ofsX ? x : x >= ptrail_ofsX + ptrail_width ? x - ptrail_width + 1: ptrail_ofsX
	ptrail_ofsY := y < ptrail_ofsY ? y : y >= ptrail_ofsY + ptrail_height ? y - ptrail_height + 1 : ptrail_ofsY
	if (oldOfsX != ptrail_ofsX || oldOfsY != ptrail_ofsY)
	{
		BitBlt(ptrail_hdc, oldOfsX - ptrail_ofsX, oldOfsY - ptrail_ofsY, ptrail_width, ptrail_height, ptrail_hdc, 0, 0,"")
		; erase the recently vacated area
		pBrushClear := Gdip_BrushCreateSolid(0xff000000)
		if (pTrail_ofsX < oldOfsX) ; erase left side
			Gdip_FillRectangle(ptrail_G, pBrushClear, 0, 0,  oldOfsX - ptrail_ofsX, ptrail_height)
		else if (pTrail_ofsX > oldOfsX) ; erase right side
			Gdip_FillRectangle(ptrail_G, pBrushClear, ptrail_width - (ptrail_ofsX - oldOfsX), 0, ptrail_ofsX - oldOfsX, ptrail_height)
			
		if (pTrail_ofsY < oldOfsY) ; erase top
			Gdip_FillRectangle(ptrail_G, pBrushClear, 0, 0,  ptrail_width, oldOfsY - ptrail_ofsY)
		else if (pTrail_ofsY > oldOfsY) ; erase bottom
			Gdip_FillRectangle(ptrail_G, pBrushClear, 0, ptrail_height - (ptrail_ofsY - oldOfsY), ptrail_width, ptrail_ofsY - oldOfsY)
			
		Gdip_DeleteBrush(pBrushClear)
		r1 += oldOfsX - ptrail_ofsX
		r2 += oldOfsY - ptrail_ofsY
		
		scrolled := True
	}
	
	nBaseColor  := 0xff007fff
	nPen:=Gdip_CreatePen(((255)<<24)+nBaseColor, 1)
	; add a new line
	r3 := r1
	r4 := r2
	r1 := x-ptrail_ofsX
	r2 := y-ptrail_ofsY
	Gdip_DrawLine(ptrail_G, nPen,r1,r2,r3,r4)
	Gdip_DeletePen(nPen)
Return

Fade:
	; fade the drawing
	Matrix =
	( LTrim Join
		1|0|0|0|0|
		0|1|0|0.5|0|
		0|0|1|1|0|
		0|0|0|0|0|
		-0.004|-0.004|-0.004|0|1
	)
	
	pTrail_bitmap := Gdip_CreateBitmapFromHBITMAP(ptrail_hbm)
	Gdip_GraphicsClear(ptrail_G)
	Gdip_DrawImage(ptrail_G, pTrail_bitmap,"","","","","","","","",Matrix)
	Gdip_DisposeImage(pTrail_bitmap)
	scrolled := False
Return

updateimage:
	if (scrolled)
		Gosub Fade
	else
		UpdateLayeredWindow(ptrail_hWnd, ptrail_hdc, ptrail_ofsX, ptrail_ofsY, ptrail_width, ptrail_height, 64)
Return

Gdip_DrawImageKeyed(pGraphics, pBitmap, dx="", dy="", dw="", dh="", sx="", sy="", sw="", sh="", Matrix=1, ColorLow=0x00000000, ColorHigh=0xff0000ff)
{
	if (Matrix&1 = "")
		ImageAttr := Gdip_SetImageAttributesColorMatrix(Matrix)
	else if (Matrix != 1)
		ImageAttr := Gdip_SetImageAttributesColorMatrix("1|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|0|" Matrix "|0|0|0|0|0|1")
		
	if ImageAttr
		Gdip_DisposeImageAttributes(ImageAttr)
		
	DllCall("gdiplus\GdipCreateImageAttributes", "uint*", ImageAttr)
	stat := DllCall("gdiplus\GdipSetImageAttributesColorKeys", "uint", ImageAttr, "int", 1, "int", 0, "int", ColorLow, "int", ColorHigh)
	
	if (sx = "" && sy = "" && sw = "" && sh = "")
	{
		if (dx = "" && dy = "" && dw = "" && dh = "")
		{
			sx := dx := 0, sy := dy := 0
			sw := dw := Gdip_GetImageWidth(pBitmap)
			sh := dh := Gdip_GetImageHeight(pBitmap)
		}
		else
		{
			sx := sy := 0
			sw := Gdip_GetImageWidth(pBitmap)
			sh := Gdip_GetImageHeight(pBitmap)
		}
	}

	E := DllCall("gdiplus\GdipDrawImageRectRect", "uint", pGraphics, "uint", pBitmap
	, "float", dx, "float", dy, "float", dw, "float", dh
	, "float", sx, "float", sy, "float", sw, "float", sh
	, "int", 2, "uint", ImageAttr2, "uint", 0, "uint", 0)
	if ImageAttr
		Gdip_DisposeImageAttributes(ImageAttr)
	return E
}