GDI+ standard library 1.45 by tic
I have read binary data from a file. Internally I store it in a var in Hex format.
When I write this data to a binary file with BinWrite() by Laszlo, the file is ok and from there I can use your GDI+ Lib to CreateBitmapFromFile(). But for this I need this temporary binary file. How can I create a Bitmap directly from the hex or binary data stored in the variable of my script? Is it possible?
Thanks a lot for your advice.
toralf
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.
I've just discovered an easy way to add blur behind a layered window (Vista/Win7):
VarSetCapacity(struct, 3, 0) NumPut(1,struct,0,"UInt") NumPut(0x1,struct,1,"UInt") DllCall("dwmapi.dll\DwmEnableBlurBehindWindow", "UInt", hwnd,"UInt",&struct)
Unfortunately, it doesn't work - in my case, at least - for the first created window. The following windows have blur...
hData := DllCall("GlobalAlloc", "UInt", 2, "UInt", FileInfo2) pData := DllCall("GlobalLock", "UInt", hData) DllCall("RtlMoveMemory", "UInt", pData, "UInt", &BRAFromMemIn+Info2+FileInfo1, "UInt", FileInfo2) 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) return pBitmap
where FileInfo2 is the size in bytes of the image and &BRAFromMemIn+Info2+FileInfo1 is the address in memory of the beginning of the image.
You might want to take a look at the as of yet unreleased BRA library a couple of posts back. I am really sorry about this anyone that cares! I am overworked! I will try and release it properly soon
But I couldn't get it working. Hence, I posted in the Ask for help section: <!-- w -->www.autohotkey.com/forum/topic54465.html<!-- w -->
toralf
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.
See this hand clock:
In this script, the rotating point is in the middle of png, so I must chage it somewhere else ofcourse.
How :?: I can't get it work...
#SingleInstance, Force #NoEnv SetBatchLines, -1 ; Create a layered window (+E0x80000 : must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption ; This will be used as the 2nd gui so that we can show our image on it Gui, 2: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs Gui, 2: Show, NA hwnd2 := WinExist() OnMessage(0x201, "WM_LBUTTONDOWN") ;_______________________________________________________________________________________________ #Include, Gdip.ahk If !pToken := Gdip_Startup() { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } if !FileExist("hand.png") UrlDownloadToFile, http://img11.imageshack.us/img11/5531/image9yq.png, hand.png file := A_ScriptDir . "\hand.png" Loop,1000 { Angle:=A_Index Gosub go } return ;___________________________GDI+ important stuff__________________________________________________ Return ;##################################################################### Go: ; If the file in the edit field is not a valid image then return If !pBitmap := Gdip_CreateBitmapFromFile(File) Return ; We should get the width and height of the image, in case it is too big for the screen then we can resize it to fit nicely OriginalWidth := Gdip_GetImageWidth(pBitmap), OriginalHeight := Gdip_GetImageHeight(pBitmap) Ratio := OriginalWidth/OriginalHeight ; If the image has a width larger than 1/2 of the width of the screen or height larger than 1/2 the screen, then we will resize it to be half of the screen If (OriginalWidth >= A_ScreenWidth//2) || (OriginalHeight >= A_ScreenHeight//2) { If (OriginalWidth >= OriginalHeight) Width := A_ScreenWidth//2, Height := Width*(1/Ratio) Else Height := A_ScreenHeight//2, Width := Height*Ratio } Else Width := OriginalWidth, Height := OriginalHeight ; Width and Height now contain the new dimensions the image on screen will be ; When rotating a square image, then the bitmap or canvas will need to be bigger as you can imagine that once rotated then a triangle will be wider than a square ; We need to know the new dimensions of the image ; With Gdip_GetRotatedDimensions we can plug in the width and height of the image, and the angle it is to be rotated by ; The last 2 parameters are the variables in which tio store the new width and height of the rotated image ; RWidth and RHeight now contain the dimensions of the rotated image Gdip_GetRotatedDimensions(Width, Height, Angle, RWidth, RHeight) ; We rotate an image about the top left corner of the image, however this will result in the image moving off the canvas ; We can use Gdip_GetRotatedTranslation to find how much the image should be 'shifted' by in the x and y coordinates in order for it to be back on the canvas ; As with the above function, we plug in the width, height and angle to rotate by ; The function will then make the last 2 parameters the x and y translation (this is the distance in pixels the image must be shifted by) ; xTranslation and yTranslation now contain the distance to shift the image by Gdip_GetRotatedTranslation(Width, Height, Angle, xTranslation, yTranslation) ; We will now create a gdi bitmap to display the rotated image on the screen (as mentioned previously we must use a gdi bitmap to display things on the screen) hbm := CreateDIBSection(RWidth, RHeight) ; Get a device context compatible with the screen hdc := CreateCompatibleDC() ; Select the bitmap into the device context obm := SelectObject(hdc, hbm) ; Get a pointer to the graphics of the bitmap, for use with drawing functions, ; and set the InterpolationMode to HighQualityBicubic = 7 so that when resizing the image still looks good G := Gdip_GraphicsFromHDC(hdc), Gdip_SetInterpolationMode(G, 7) ; We can now shift our graphics or 'canvas' using the values found with Gdip_GetRotatedTranslation so that the image will be drawn on the canvas Gdip_TranslateWorldTransform(G, xTranslation, yTranslation) ; We can also rotate the graphics by the angle we desire Gdip_RotateWorldTransform(G, Angle) ; If we wish to flip the image horizontally, then we supply Gdip_ScaleWorldTransform(G, x, y) with a negative x transform ; We multiply the image by the x and y transform. So multiplying a direction by -1 will flip it in that direction and 1 will do nothing ; We must then shift the graphics again to ensure the image will be within the 'canvas' ; You can see that if we wish to flip vertically we supply a negative y transform If Horizontal Gdip_ScaleWorldTransform(G, -1, 1), Gdip_TranslateWorldTransform(G, -Width, 0) If Vertical Gdip_ScaleWorldTransform(G, 1, -1), Gdip_TranslateWorldTransform(G, 0, -Height) ; As you will already know....we must draw the image onto the graphics. We want to draw from the top left coordinates of the image (0, 0) to the top left of the graphics (0, 0) ; We are drawing from the orginal image size to the new size (this may not be different if the image was not larger than half the screen) Gdip_DrawImage(G, pBitmap, 0, 0, Width, Height, 0, 0, OriginalWidth, OriginalHeight) ; Even though this is not necessary in this scenario, you should always reset the transforms set on the graphics. This will remove any of the rotations Gdip_ResetWorldTransform(G) ; We will update the hwnd with the hdc of our gdi bitmap. We are drawing it at the new width and height and in the centre of the screen UpdateLayeredWindow(hwnd2, hdc, (A_ScreenWidth-RWidth)//2, (A_ScreenHeight-RHeight)//2, RWidth, RHeight) ; As always we will dispose of everything we created ; So we select the object back into the hdc, the delete the bitmap and hdc SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc) ; We will then dispose of the graphics and bitmap we created Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmap) Return ;##################################################################### WM_LBUTTONDOWN(){ If (A_Gui = 2) PostMessage, 0xA1, 2 } ;##################################################################### Esc:: GuiClose: Exit: Gdip_Shutdown(pToken) ExitApp Return
In this line:
; We will update the hwnd with the hdc of our gdi bitmap. We are drawing it at the new width and height and in the centre of the screen
UpdateLayeredWindow(hwnd2, hdc,(A_ScreenWidth-RWidth)//2, (A_ScreenHeight-RHeight)//2, RWidth, RHeight)
"GDI+ uses matrix transformations for that purpose, so if you want to rotate around a point other than (0,0), that is a combination of a translation and a rotation (http://en.wikipedia....ormation_matrix), i.e.
graphics.TranslateTransform( 0 - (rc.right - rc.left)/2 , 0 - (rc.bottom - rc.top)/2, MatrixOrderPrepend);
graphics.RotateTransform(some_angle,MatrixOrderPrepend);
And it is the nature of a matrix transformation that it is applied to the whole image, so if you only want to use a part of a DC, you have to "cut" that part for this purpose."
Thx for your great library, it was really helpful to me.
I have a question about performance and optimization.
Let's say I have a static graphic ( a png picture for example ) and some dynamic text to show above the picture.
So there are two layers and if I'm not wrong, I can't show a classic gui window above a gdip window.
I have tried two ways :
1/ One single gui window with the two layers updated each time the text needs to be changed.
2/ Two gui windows, one with the png background and one with the text.
Both solution are working great with a simple example like this, but when you add more dynamic layers I think it will be better to use the fastest one.
How would you do this ?
Razer
About method #2, I use GUI +owner and transparency, but we are limited to 1 main gui and 49 gui layers, CPU consommation is good but if you are on vista it's dwm.exe that use CPU not your script , and guicontrol, move, mycontrol is very fast without redraw...
Im honestly very glad the library has been helpful to you
If you are able, would you be able to post what code you have or an example of what you are currently doing and I will try and get some time and show you how I would do it
Guest
You should really sign up if you havent already
Ok, you are exactly right. the easiest way to achive this would be to create a modified Gdip_GetRotatedTranslation but have the byref outputs as xPos and yPos to be used with UpdateLayeredWindow, instead of the amount to shift by. I will try and get round to this as well, but you might wanna give the whole trig thing a bash yourself with that, or if anyone else can help out, that would be great!
Here is an example of the 2nd method :
; -------------------------------------------------------------------------------------------------- ; GENERAL SETTINGS ; -------------------------------------------------------------------------------------------------- #noenv setbatchlines -1 listlines Off #singleinstance force #include Gdip.ahk settimer UpdateLabel, 200 onexit ExitLabel ; -------------------------------------------------------------------------------------------------- ; DEFINITIONS ; -------------------------------------------------------------------------------------------------- GUI_BG := 10 GUI_FG := 20 WIN_BG := "WIN_BACKGROUND" WIN_FG := "WIN_FOREGROUND" WIN_ID_BG := "Background" WIN_ID_FG := "Foreground" skin_file = %A_ScriptDir%\Skin.png initialize() ; -------------------------------------------------------------------------------------------------- ; FONCTIONS ; -------------------------------------------------------------------------------------------------- initialize() { global local retour := 0 If !pToken := Gdip_Startup() { msgbox 48, initialize : Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } init_background() init_foreground() return retour } init_background() { global local retour := 0 ; Create a layered window (+E0x80000 : must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption gui %GUI_BG%: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs ; Show the window gui %GUI_BG%:show, NA, %WIN_BG% ; Get a handle to this window we have created in order to update it later WIN_ID_BG := WinExist() update_layer( WIN_ID_BG ) return retour } init_foreground() { global local retour := 0 ; Create a layered window (+E0x80000 : must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption gui %GUI_FG%: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs ; Show the window gui %GUI_FG%:show, NA, %WIN_FG% ; Get a handle to this window we have created in order to update it later WIN_ID_FG := WinExist() update_layer( WIN_ID_FG ) return retour } update_layer( layer_name ) { global local retour := 0 font := "" options = "" current_time := "" ; --------------------------------- ; Loading of the background picture ; --------------------------------- if ( layer_name == WIN_ID_BG ) { p_bitmap := Gdip_CreateBitmapFromFile( skin_file ) If !p_bitmap { MsgBox, 48, update_layer : Could not load the image <%skin_file%> ExitApp } } ; ---------------------------------- ; Creation of the graphic ressources ; ---------------------------------- hbm := CreateDIBSection(300, 150) hdc := CreateCompatibleDC() obm := SelectObject(hdc, hbm) p_graphic := Gdip_GraphicsFromHDC(hdc) Gdip_SetInterpolationMode(p_graphic, 7) ; ------------------------------- ; Update of the background window ; ------------------------------- if ( layer_name == WIN_ID_BG ) { Gdip_DrawImage(p_graphic, p_bitmap, 0, 0, 300, 150, 0, 0, 300, 150) UpdateLayeredWindow(WIN_ID_BG, hdc, 0, 0, 300, 150) } ; ------------------------------- ; Update of the foreground window ; ------------------------------- if ( layer_name == WIN_ID_FG ) { font := "Arial" options = x0 y75 w300 h0 cFF000000 Center Normal r4 s18 formattime current_time,, HH:mm:ss Gdip_TextToGraphics(p_graphic, current_time, options, font) UpdateLayeredWindow(WIN_ID_FG, hdc, 0, 0, 300, 150) } ; ------------------------- ; Delete graphic ressources ; ------------------------- SelectObject(hdc, obm) DeleteObject(hbm) DeleteDC(hdc) Gdip_DeleteGraphics(p_graphic) if ( layer_name == WIN_ID_BG ) { Gdip_DisposeImage(p_bitmap) } return retour } ; -------------------------------------------------------------------------------------------------- ; LABELS ; -------------------------------------------------------------------------------------------------- UpdateLabel: update_layer( WIN_ID_FG ) return ExitLabel: Gdip_Shutdown(pToken) ExitApp return
Before running the script don't forget to download this picture :
It's a very basic example, just a png background and the current time.
My question is still the same, is there a better (faster) way to do this?
Zaelia :
The first method would have been to have a single window with the picture and the text updating together. I think it is not the best solution because when you work with bigger pictures and with multiple pictures into the same window it is useless to waste memory and cpu updating static objects. Maybe I'm totally wrong, so if anyone have a better solution than the two I've presented, feel free to post.
Razer.
Also, it may help you to look at example 11 as it is very similar to what you are writing
you will need:
Download: BRA Library
Although it is still incomplete
I've read your tutorial 11 and I'll try your region clipping method with a single gui to see if it's possible to use it with my script. I really hope so.
It would be great because I'm developping a google quick search bar like tool and right now I have 1 main gui window and 4 others which I have to move together when dragging.
It works quite well but it would be much easier and smoother to have everything running into a single gui.
Here you can find some screen and explanation of what I'm working on :
http://executor.21.f...topic.php?t=716
I think when I will have something good enough I'll post my tool here.
Anyway, I have two other problems I haven't solved, maybe someone has already figured these out?
1/ How to have an animation gif bitmap playing with gdip library?
I thought using Gdip_CreateBitmapFromFile, Gdip_DrawImage and UpdateLayeredWindow would work but it doesn't seem to.
BRA files could be a solution, I will test it later if nothing about the gif comes out.
2/ Since it's not possible to have a classic gui input box onto a mutli layered window, I had to simulate one for my tool.
I'm using a Gdip_TextToGraphics and scanning keystrokes to update this text. Porblem is when the input is too big the text is returning to the line.
Is it posible to have the text to be clipped at the left side like a classic input box?
Razer.
What is the fastest method for draw ? gdidrawimage, bitblt or setimage ? I do not know which to use for a very fast update (30fps w640 h480) ...