Sign in to follow this  
Followers 0
mikell

GDI+ and png animation

6 posts in this topic

Hello

I'm trying to make a desktop animation, which uses 1800 png files with transparency, around 20 Ko each.

Here is the piece of script :

_GDIPlus_Startup()
For $i = 0 to 1800
    $hImage = _GDIPlus_ImageLoadFromFile($path & $i & ".png")
    SetBitMap($hGUI, $hImage, 255)
    GUISetState()
    _GDIPlus_ImageDispose($hImage)
    Sleep(20)
Next
_GDIPlus_Shutdown()

It works, but I can see my HD working hard and the anim is slow.

But, when I play the anim a second time, then it plays correctly and my HD keeps quiet.

I suppose there is some kind of writing in a cache when the images "load" the first time, and a simple read of this cache the second time.

If before the script I put this :

For $i = 0 to 1800
    $hImage = _GDIPlus_ImageLoadFromFile($path & $i & ".png")
    _GDIPlus_ImageDispose($hImage)
Next

then there is a (long) silent loading and after this the anim plays correctly.

So my question is : is it possible to avoid this delay before playing, and to play the anim in a "progressive" way ? or, is there a way to reduce this caching delay ?

I found some things about using libpng.dll but I dont know how to put this to Autoit...

Thanks a lot for any information

Merry Xmas to all ;)

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Hello

I'm trying to make a desktop animation, which uses 1800 png files with transparency, around 20 Ko each.

Here is the piece of script :

_GDIPlus_Startup()
For $i = 0 to 1800
    $hImage = _GDIPlus_ImageLoadFromFile($path & $i & ".png")
    SetBitMap($hGUI, $hImage, 255)
    GUISetState()
    _GDIPlus_ImageDispose($hImage)
    Sleep(20)
Next
_GDIPlus_Shutdown()

It works, but I can see my HD working hard and the anim is slow.

But, when I play the anim a second time, then it plays correctly and my HD keeps quiet.

I suppose there is some kind of writing in a cache when the images "load" the first time, and a simple read of this cache the second time.

If before the script I put this :

For $i = 0 to 1800
    $hImage = _GDIPlus_ImageLoadFromFile($path & $i & ".png")
    _GDIPlus_ImageDispose($hImage)
Next

then there is a (long) silent loading and after this the anim plays correctly.

So my question is : is it possible to avoid this delay before playing, and to play the anim in a "progressive" way ? or, is there a way to reduce this caching delay ?

I found some things about using libpng.dll but I dont know how to put this to Autoit...

Thanks a lot for any information

Merry Xmas to all ;)

I would try something like (though I haven't)

$frameTime = 20
$playTime = 1801 * $frametime
$TimeToload=0
$Frame = 0
OnAutoItExitRegister("clean")
Dim $hImage[1801] 
_GDIPlus_Startup()
$startTime = TimerInit()
$playing = false

For $i = 0 to 1800;should this really be from 0?
 $hImage[$i] = _GDIPlus_ImageLoadFromFile($path & $i & ".png")
 if not $playing and $i>10 then ; maybe 10 is too few?
 $Avtime = TimerDiff($startTime)/($i+1)
 $TimeToLoad = (1801-$1)*$Avtime
 if $TimeToLoad < $playTime then ; + $someSafetyMargin?
 AdlibRegister("Play",$frameTime)
 $playing = True
 endif
 endif
Next

while 1
 sleep(100)
 if $frame >= 1801 then exit
next

Func Play()
 SetBitMap($hGUI, $hImage[$frame], 255)
 GUISetState();is this needed?
 
 ;possibly dispose of last image here
 ;_GDIPlus_ImageDispose($hImage[$Frame])

 $frame += 1
wend

Func Clean()
For $i = 0 to 1800
 _GDIPlus_ImageDispose($hImage[$i])
 
Next

_GDIPlus_Shutdown()

EDIT: Welcome to the AutoIt forums mikell :evil:

Edited by martin

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

Thanks martin for your answer

"should this really be from 0?"

No, you're right, my first image is ' 0.png' but $hImage[0] doesn't work.

In fact my anim is 1875 images long, it begins (now) at '1.png' and ends at '1874.png'.

I could manage your script in this way :

$frameTime = 20
$playTime = 1874 * $frametime
$TimeToload=0
$Frame = 0
;Opt("OnExitFunc", "clean")
 Dim $hImage[1875]
_GDIPlus_Startup()
$startTime = TimerInit()
$playing = false

For $i = 1 to 1874   ;should this really be from 0?
 $hImage[$i] = _GDIPlus_ImageLoadFromFile($path & $i & ".png")
 If not $playing and $i>10 Then ; maybe 10 is too few?
    $Avtime = TimerDiff($startTime)/($i+1)
    $TimeToLoad = (1875-$i)*$Avtime
    If $TimeToLoad < $playTime Then      ; + $someSafetyMargin?
        AdlibEnable("Play",$frameTime)
        $playing = True
    Endif
 Endif
 $frame += 1
Next

while 1
 sleep(100)
 If $frame >= 1874 Then 
    Clean()
    Exit
Endif
wend

_GDIPlus_Shutdown()

Func Play()
 SetBitMap($hGUI, $hImage[$frame], 255)
EndFunc

Func Clean()
For $i = 1 to 1874
 _GDIPlus_ImageDispose($hImage[$i])
Next
EndFunc

it's much better, but now there is a funny thing occuring : the first time the anim plays correctly, and the second time it runs like a rocket ;)

Is there a way for the anim to "learn" if it is its first run or not, maybe by detecting if images are already loaded in cache ?

The problem is, I have absolutely no idea about how to do that...

Share this post


Link to post
Share on other sites

Thanks martin for your answer

"should this really be from 0?"

No, you're right, my first image is ' 0.png' but $hImage[0] doesn't work.

In fact my anim is 1875 images long, it begins (now) at '1.png' and ends at '1874.png'.

I could manage your script in this way :

$frameTime = 20
$playTime = 1874 * $frametime
$TimeToload=0
$Frame = 0
;Opt("OnExitFunc", "clean")
 Dim $hImage[1875]
_GDIPlus_Startup()
$startTime = TimerInit()
$playing = false

For $i = 1 to 1874 ;should this really be from 0?
 $hImage[$i] = _GDIPlus_ImageLoadFromFile($path & $i & ".png")
 If not $playing and $i>10 Then ; maybe 10 is too few?
    $Avtime = TimerDiff($startTime)/($i+1)
    $TimeToLoad = (1875-$i)*$Avtime
    If $TimeToLoad < $playTime Then ; + $someSafetyMargin?
        AdlibEnable("Play",$frameTime)
        $playing = True
    Endif
 Endif
 $frame += 1
Next

while 1
 sleep(100)
 If $frame >= 1874 Then 
    Clean()
    Exit
Endif
wend

_GDIPlus_Shutdown()

Func Play()
 SetBitMap($hGUI, $hImage[$frame], 255)
EndFunc

Func Clean()
For $i = 1 to 1874
 _GDIPlus_ImageDispose($hImage[$i])
Next
EndFunc

it's much better, but now there is a funny thing occuring : the first time the anim plays correctly, and the second time it runs like a rocket ;)

Is there a way for the anim to "learn" if it is its first run or not, maybe by detecting if images are already loaded in cache ?

The problem is, I have absolutely no idea about how to do that...

I don't see how you run the second time. If you simply run the whole script again for th esecond time then I think that Windows is caching the data read from the disc. If the $frametime value is the same then I don't see how it runs faster the second time, unless you mean it starts sooner in which case I do understand. But to run again it would be better just to set the frame count to 0 and let the adlib carry on, then it would also be very quick to start providing you hadn't disposed of the graphic handles.

This will make the animation run 3 times.

$frameTime = 20
$playTime = 1874 * $frametime
$TimeToload=0
$Frame = 0
;Opt("OnExitFunc", "clean")
 Dim $hImage[1875]
_GDIPlus_Startup()
$startTime = TimerInit()
$playing = false
For $jj = 1 to 3
For $i = 1 to 1874 ;should this really be from 0?
 $hImage[$i] = _GDIPlus_ImageLoadFromFile($path & $i & ".png")
 If not $playing and $i>10 Then ; maybe 10 is too few?
    $Avtime = TimerDiff($startTime)/($i+1)
    $TimeToLoad = (1875-$i)*$Avtime
    If $TimeToLoad < $playTime Then ; + $someSafetyMargin?
        AdlibEnable("Play",$frameTime)
        $playing = True
    Endif
 Endif
 $frame += 1
Next
$frame = 0
Next
while 1
 sleep(100)
 If $frame >= 1874 Then 
    Clean()
    Exit
Endif
wend

_GDIPlus_Shutdown()

Func Play()
 SetBitMap($hGUI, $hImage[$frame], 255)
EndFunc

Func Clean()
For $i = 1 to 1874
 _GDIPlus_ImageDispose($hImage[$i])
Next
EndFunc

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

martin, to play the anim I run the whole script, and this script automatically exits at the end of the anim.

At the first run, the anim plays well but I see my HD at work, so I suppose that Windows is loading the images "somewhere" and memorizing "something", because if I run the script a second time (or more) then the anim plays much quicker.

If I reboot my PC and run the script, it works as a first run. I think the "somewhere" and the "something" has been cleaned up during the reboot.

If I could know about these "somewhere" and "something" then I should include in the script a condition for playing the anim in 2 different ways.

My english is approximative so forgive me if my explanations are not very clear

Share this post


Link to post
Share on other sites

Pfff impossible to learn where GDI+ memorizes these data

There is a solution, it is tricky and not satisfying but I tested it several times and it works

$frameTime = 30
$playTime = 1874 * $frametime
$TimeToload=0
$Frame = 0
 Dim $hImage[1875]
_GDIPlus_Startup()
$startTime = TimerInit()
$playing = false

For $i = 1 to 1874 
$test = TimerInit()
$hImage[$i] = _GDIPlus_ImageLoadFromFile($path & $i & ".png")
If TimerDiff($test) < 5 Then        ; <---------------------------- here is the trick
    SetBitMap($hGUI, $hImage[$i], 255)
    _GDIPlus_ImageDispose($hImage[$i])
    Sleep(20)
Else
    If not $playing and $i>10 Then 
        $Avtime = TimerDiff($startTime) /($i+1)
        $TimeToLoad = (1875-$i)*$Avtime
        If $TimeToLoad < $playTime Then    
            AdlibEnable("Play",$frameTime)
            $playing = True
        Endif
     Endif
 Endif
 $frame += 1
Next

while 1
 sleep(100)
 If $frame >= 1874 Then 
    Clean()
    Exit
Endif
wend

_GDIPlus_Shutdown()

Func Play()
 SetBitMap($hGUI, $hImage[$frame], 255)
EndFunc

Func Clean()
For $i = 1 to 1874
 _GDIPlus_ImageDispose($hImage[$i])
Next
EndFunc

something like :

If (ImageLoadingTime < 5) then

my original script

else

martin's script

endif

;) thank you martin, have nice Xmas and new year

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0