Jump to content

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

DevIL il_loadimage() Load images not supported by ahk


  • Please log in to reply
15 replies to this topic
foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Ever wanted to display other imagetypes than the standart one AHK/Windows supports? Here is how.


il_loadimage.ahk:
/*
************
* IL_LOADIMAGE_VERSION = 1.30
* by foom
*
* v1.00 - 28.05.06
* -Released
* v1.10 - 28.05.06
* -Rewrote the function to add positioning params
* v1.16 - 29.05.06
* -Changed the way positioning works. Much more felxible now.
* v1.30 - 03.06.06
* -Added cleanup routines to main function.
* -Changed DeleteDC to ReleaseDC.
* -Changed how shutdown works. Look inside the examplescript for how to use it.
* -The defaultimage will now be created by il_init().
*
* Requirements:
* *Min. AHKVersion = 1.0.43.08
* *This script needs the latest(April 18, 2006) DevIL.dll ILU.dll, ILUT.dll to run.
*  You can get them here "http://openil.sourceforge.net" if you don't have them allready
*  and place them into your scripts directory.
*
* Planned:
* *If a function like this "http://www.autohotkey.com/forum/viewtopic.php?t=9904" will be inplemented in AHK
*  it will be even eaier to use this script because one would not have to find the name of the control with windowspy.
* *Create a function which will wrap the "Gui, Add, Pic" command
*
* Comments:
* *Originaly i had the idea to load images with IL and draw them with GDI functions
*  which wouldn't be comfortable since WM_PAINT messages would need to be used to redraw the image.
*  Thanks to PhiLho who came up with this idea "http://www.autohotkey.com/forum/viewtopic.php?t=9932"
*  and Chris who came up with a solution it turned out pretty easy in relation to my first approach.
********************************************************
*/

;_file is the name of the image.
;_static is the name of the picturecontrol. You can find it with the windowspy/AU3_Spy utility.
;_vName is unused now but would simplyfy and replace the use of _static if hwnd could be retrieved thru _vName.
;_x _y _w _h are selfexplantionary.
;""(blank) for any posparam leaves the pos/size as is. -1 for _w or _h will preserve aspectratio while -1 for both will load the image at the original size.
;_GuiNum is the number of the Gui to work in (optional)
;bShutdown is only used to free recources. The only valid value for this param is the string "shutdown".
;Please look into the examplescript for instructions on how to use it.

il_loadimage(_file,_static,_x,_y,_w,_h,_GuiNum=1,_bShutdown="")
{
;IL_IMAGE_WIDTH          = 0x0DE4
;IL_IMAGE_HEIGHT         = 0x0DE5
;illoadimage = DevIL\ilLoadImage
;ilgetinteger = DevIL\ilGetInteger

    global hMod_ILUT

;remember the handle between calls and save a copy for cleanup

    static il_hbitmap
    old_il_hbitmap:=il_hBitmap

;handle shutdown
;use the il_loadimage function to do the big cleanup since the handles are declared private

    if (_bShutdown = "shutdown")
    {
        il_shutdown(il_hBitmap,hMod_ILUT)
        return
    }

    Gui %_GuiNum%: +LastFound
    ControlGet, hStatic, Hwnd,, %_static%
    GuiControlGet, _StaticSize, Pos, %_static%

;create a DC to put our hBitmap in.
    
    il_ScreenDC:=DllCall("GetDC", uint, hStatic)

;load image from disk and create a hbitmap from it.

    DllCall("DevIL\ilLoadImage", str, _file)
    il_hBitmap:=DllCall("ILUT\ilutConvertToHBitmap", uInt, il_ScreenDC)
    ;il_hBitmap:=DllCall("ILUT\ilutWinLoadImage", str, _file, uInt, il_ScreenDC)

;place the hbitmap into the static

    SendMessage, 0x172, 0, il_hBitmap, ,ahk_id %hStatic%   ; 0x172 is STM_SETIMAGE
    if errorlevel                                          ; get the returned hbitmap for cleanup
    old_hbitmap:=errorlevel

;compute size

    il_w:=DllCall("DevIL\ilGetInteger", uInt, 0x0DE4)
    il_h:=DllCall("DevIL\ilGetInteger", uInt, 0x0DE5)

    if (_w=-1 and _h=-1)
    {
        _StaticSizeW:=il_w
        _StaticSizeH:=il_h
    }
    else if (_w=-1 or _h=-1)
    {
        if _h=
           _h=%_StaticSizeH%
        if _w=
           _w=%_StaticSizeW%
        if _w=-1
           _w:=round(il_w/(il_h/_h))
        if _h=-1
           _h:=round(il_h/(il_w/_w))
    }

    if _w>=0
        _StaticSizeW:=_w
    if _h>=0
        _StaticSizeH:=_h
    if _x!=
        _StaticSizeX:=_x
    if _y!=
        _StaticSizeY:=_y

    GuiControl, MoveDraw, %_static%, x%_StaticSizeX% y%_StaticSizeY% w%_StaticSizeW% h%_StaticSizeH%
    
;cleanup
    if ( old_hbitmap and (old_hbitmap != il_hbitmap) )
    {
       ret:=DllCall("DeleteObject", uInt,old_hbitmap)
       ;msgbox, `nnew hBitmap: %il_hbitmap% `nold hBitmap: %old_hbitmap% `ndeleted successfull: %ret% `nerrorelevel: %errorlevel%
    }
    if ( old_il_hbitmap and (old_il_hbitmap != il_hbitmap) )
    {
       ret:=DllCall("DeleteObject", uInt,old_il_hbitmap)
       ;msgbox, `nnew hBitmap: %il_hbitmap% `nold hBitmap: %old_il_hbitmap% `ndeleted successfull: %ret% `nerrorelevel: %errorlevel%
    }
    if il_ScreenDC
    {
       ret:=DllCall("ReleaseDC", UInt,hStatic, UInt,old_il_ScreenDC)
       ;msgbox, `nnew DC: %il_ScreenDC% `nold DC: %old_il_ScreenDC% `ndeleted successfull: %ret% `nerrorelevel: %errorlevel%
    }
}

;############################################################
;This does not work ATM, don't touch!
; il_getDims(_file,_p2)
; {
;      DllCall("DevIL\ilBindImage", uInt, 2)
;      DllCall("DevIL\ilLoadImage", str, _file)
; 
;      if _p2 = w
;         result:=DllCall("DevIL\ilGetInteger", uInt, 0x0DE4)
; else if _p2 = h
;         result:=DllCall("DevIL\ilGetInteger", uInt, 0x0DE5)
;      
;      DllCall("DevIL\ilBindImage", uInt, 1)
;
;      return result
; }
;############################################################

;Initialize IL
il_init()
{
; ILUT_WIN32              = 2
; IL_ORIGIN_MODE          = 0x0603
; IL_ORIGIN_UPPER_LEFT    = 0x0602
; IL_ORIGIN_SET           = 0x0600
; IL_FORMAT_SET           = 0x0610
; ilinit = DevIL\ilInit
; ilenable = DevIL\ilEnable
; ilsetinteger = DevIL\ilSetInteger
; ilutinit = ILUT\ilutInit
; ilutrenderer = ILUT\ilutRenderer
; ilutwinloadimage = ILUT\ilutWinLoadImage

    hMod_ILUT := DllCall("LoadLibrary", "str", "ILUT.dll")
    ;hMod_DevIL := DllCall("LoadLibrary", "str", "DevIL.dll")
    DllCall("DevIL\ilInit")
    DllCall("ILUT\ilutInit")
    DllCall("ILUT\ilutRenderer", uint,2)
    DllCall("DevIL\ilEnable", uint, 0x0610)
    DllCall("DevIL\ilEnable", uint, 0x0600)
    DllCall("DevIL\ilSetInteger", uint, 0x0603, uint, 0x0602)
    DllCall("DevIL\ilGenImages", uInt, 1, uInt, 1)
    DllCall("DevIL\ilBindImage", uInt, 1)
    
    IfNotExist, iltmp.jpg
    {
        DllCall("DevIL\ilDefaultImage")
        DllCall("DevIL\ilSaveImage", str, "iltmp.jpg")
    }

}

;this function is used internal by il_loadimage and is only here not to clutter the main function too much.

il_shutdown(il_hBitmap,hMod_ILUT)
{
    DllCall("DeleteObject", UInt,il_hBitmap)
    ;DllCall("DeleteDC", UInt,0, UInt,il_ScreenDC)
    ;DllCall("FreeLibrary", "UInt", hMod_DevIL)
    DllCall("FreeLibrary", "UInt", hMod_ILUT)
}
;http://openil.sourceforge.net/docs/index.php for technical information on IL

il_imageload_example.ahk:
#singleinstance force
#include il_loadimage.ahk

;init IL. Put that function at the top of your script.
il_init()

;load an image the usual ahkway first. Il_init() will create iltmp.jpg in %A_WorkingDir%.
;This is necessary since we will use the control this creates to put our image inside.
Gui, -Margin BackgroundTrans
Gui, Add, Picture, x y w640 h640 vthepicture, iltmp.jpg  ;using our iltmp.jpg


return

!+l::

;DevIL supports following formats for loading:
;.bmp, .cut, .dds, .doom, .gif, .ico, .jpg, .lbm, .mdl, .mng, .pal, .pbm, .pcd, .pcx, .pgm, .pic, .png, .ppm, .psd, .psp, .raw, .sgi, .tga and .tif .hdr
;*Note*
;Animated gifs are not supported in il_loadimage. It will only load the first frame.
FileSelectFile, aFile, , , Some Files DevIL supports..., Images (*.tga; *.psd; *.jpg; *.png; *.bmp; *.gif; *.tif; *.dds)
If !aFile
   return
il_loadimage(aFile,"static1","","",640,-1)
Gui, Show,  center autosize
return

^!l::
aFile=
FileSelectFile, aFile, , , Load windows XP supported formats..., Images (*.jpg; *.png; *.bmp; *.gif; *.tif;)
If !aFile
   return
GuiControl, , thepicture, *w640 *h-1 %aFile%
Gui, Show,  center autosize
return

GuiClose:

;cleanup/release stuff
;use the il_loadimage function in the following manner to release the resources used by the il_loadimage.ahk script

    il_loadimage(0,0,0,0,0,0,0,"shutdown")
    ExitApp

return 
;http://openil.sourceforge.net/docs/index.php for technical information on IL

Here you can download a .zip with the scrits, the DevIL bins so that you can test it right away.
DOWNLOAD

***Note***
If you have images that you cannot load please zip and upload them somewhere and post a link to them so that i can analyse them.
"DO NOT" upload them to imageshack or any other "file hoster" as raw imagefiles since they compress the images. Upload them as zip,rar,7z.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Thanks for sharing it. It works, but my jpg test picture was distorted, and showed in low quality. Could you make a dialog to select the GUI size, or choose it automatically, keeping the aspect ratio, and the original size of the picture, until it fits the screen?

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Rewrote the function. Tweak the examplescript to your needs. :)

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Nice presentation. Thanks for sharing your work.

corrupt
  • Members
  • 2558 posts
  • Last active: Nov 01 2014 03:23 PM
  • Joined: 29 Dec 2004
Nice work :) .

A few things I noticed:
- It seems to have difficulty displaying some gif images for some reason.
- Instead of including a small bitmap you could also find a random .bmp in the Windows directory.
- It seems that a bitmap has to be loaded before it will display a different image (noticed more with .gif images) after an image has been loaded (I tested briefly using GuiControl to load a bitmap image before attempting to load a different image)

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Updated the script see first post.

- It seems to have difficulty displaying some gif images for some reason.

See the note in the first post.

- Instead of including a small bitmap you could also find a random .bmp in the Windows directory.

I have a much better solution. I will just create an image with IL (Woot, who would have thought of that!?!Me not in the first place :oops: )

- It seems that a bitmap has to be loaded before it will display a different image (noticed more with .gif images) after an image has been loaded (I tested briefly using GuiControl to load a bitmap image before attempting to load a different image)

Did the gif actually load correctly with ahk? Maybe the gif has a formating thats not supported by the OS or whatnot. In this case only the filename will be displayed in the static control and STM_SETIMAGE can not change the associated hbitmap of the static control.
I wonder why this is because if it would change it there would be no need for a "hack.bmp" anymore.Chris?Anyone?

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004

...if it would change it there would be no need for a "hack.bmp" anymore.Chris?Anyone?

I'm not sure, but it may help if you first do a SendMessage of STM_SETIMAGE with a 0 lParam, which should clear the control. Then try putting a new image in.

On the other hand, this might be useless for your purpose.

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Unfortunately this will not do the trick. Can you point me to the apicalls that ahk makes when you add a picture please? I would like to know what acctually makes the control display the filename if an image can not be loaded. I can only assume that in case the format is not supported the hbitmap is not created.

Edit: Does AHK Create a Text Static Control instead of a Image Static Control if the image can not be loaded? And if yes, how does it go about when you load a valid image into it afterwards? E.g. what does this command do: "GuiControl, , thepicture, *w640 *h-1 %aFile%""? Does it destroy the Textstatic and create a new Imagestatic or does it change the type of the Static and if yes how?

Edit2: How can i make the background of a Image Static Control transparent?

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004

Does AHK Create a Text Static Control instead of a Image Static Control if the image can not be loaded?

No, I think it's the API that's doing that by itself. Actually, the program stores the filename as the control's caption, so apparently when the control can't display its image, it displays its caption instead.

what does this command do: "GuiControl, , thepicture, *w640 *h-1 %aFile%""? Does it destroy the Textstatic and create a new Imagestatic or does it change the type of the Static and if yes how?

It doesn't destroy the control. Instead, it:
1) Sets the control's image to NULL (using the SendMessage I mentioned in my previous post).
2) Destroys the old icon/bitmap and loads the new one into memory.
3) Sets the control's style to be SS_BITMAP or SS_ICON via SetWindowLong.
4) Sends STM_SETIMAGE to put the new image into the control.
5) Sends STM_GETIMAGE to check if the control made a copy of the image rather than using the original verbatim. If so, it destroys its original image and memorizes the control's image (to prevent a memory leak on XP).

How can i make the background of a Image Static Control transparent?

It's been a while since I tried it, but maybe BackgroundTrans will work (might depend on image type).

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006

1) Sets the control's image to NULL (using the SendMessage I mentioned in my previous post).
2) Destroys the old icon/bitmap and loads the new one into memory.

Well since im my case th hbitmap isnt even created if i specify a invalid image i can skip these steps.Testet it with
SendMessage, 0x173, 0, 0, ,ahk_id %hStatic%
    msgbox, % errorlevel
This gives me "0".

3) Sets the control's style to be SS_BITMAP or SS_ICON via SetWindowLong.

I have tested:
"DllCall("SetWindowLong",uInt ,hStatic, int, -16, Int, 0xe)" and
"Control, Style, 0xe, %_static%", both give me the same result.
That is the Control gets a size of 0x0 and the window of my examplescript gets squashed to almost nothing because of the Autosize option.

5) Sends STM_GETIMAGE to check if the control made a copy of the image rather than using the original verbatim. If so, it destroys its original image and memorizes the control's image (to prevent a memory leak on XP).

This step confused me. You destroyed and loaded a new one allready in step 1 and 2.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Windows XP is documented as sometimes making a copy of the image you pass via STM_SETIMAGE. If this happens, there are now two copies of the image: the original that the program loaded and the one inside the control. Thus, a memory leak would occur if the control is ever given a new image. What the program does is destroy its original image so that only the one inside the control is actually consuming RAM.

I probably haven't answered all your questions. If you still have some, I can try to answer even though I'm not an expert in this area.

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Well i would like to know why the control gets resized to 0x0 when i change the style to SS_BITMAP and why i can not load pictures inside it the ahkway anymore after that.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Offhand, I don't know. It might take some experimenting to figure out the answer. If you want to know more about how picture controls are coded, I can post some of the code or e-mail it to you. Or you can download it and find the relevant sections by searching script_gui.cpp for GUI_CONTROL_PIC.

foom
  • Members
  • 386 posts
  • Last active: Jul 04 2007 04:53 PM
  • Joined: 19 Apr 2006
Thanks for taking you time but i think i'll stick to the hacky method since this is getting to complicated for me with my poor c++ experience.

However i had a look into the source and i think i understand now what it is about with the memory problem. STM_SETIMAGE doesn't delete the hbitmap that gets exchanged by it. Am i right?

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004

STM_SETIMAGE doesn't delete the hbitmap that gets exchanged by it.

That's right. It returns the old one back to you under the assumption that you might still have a use for it.