LB Booster
« Displaying animated GIFs with LBB? »

Welcome Guest. Please Login or Register.
Apr 1st, 2018, 03:46am



ATTENTION MEMBERS: Conforums will be closing it doors and discontinuing its service on April 15, 2018.
We apologize Conforums does not have any export functions to migrate data.
Ad-Free has been deactivated. Outstanding Ad-Free credits will be reimbursed to respective payment methods.

Thank you Conforums members.
Speed up Liberty BASIC programs by up to ten times!
Compile Liberty BASIC programs to compact, standalone executables!
Overcome many of Liberty BASIC's bugs and limitations!
LB Booster Resources
LB Booster documentation
LB Booster Home Page
LB Booster technical Wiki
Just BASIC forum
BBC BASIC Home Page
Liberty BASIC forum (the original)

« Previous Topic | Next Topic »
Pages: 1  Notify Send Topic Print
 thread  Author  Topic: Displaying animated GIFs with LBB?  (Read 808 times)
Harbinger
New Member
Image


member is offline

Avatar




PM

Gender: Male
Posts: 2
xx Displaying animated GIFs with LBB?
« Thread started on: Oct 16th, 2016, 03:19am »

I have asked over at the LB forums about having LB automatically animate my GIFs in a graphic window, but have not gotten a satisfactory answer for troubleshooting. I've tried the code I found on the Liberty Wiki but, while the image will load, it won't animate it.
I have also found a thread here at the LB Booster Wiki, but it's for BBC BASIC.

Can the booster help? undecided
User IP Logged

Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 1348
xx Re: Displaying animated GIFs with LBB?
« Reply #1 on: Oct 16th, 2016, 11:23am »

on Oct 16th, 2016, 03:19am, Harbinger wrote:
Can the booster help? :-/

As far as I am aware there are basically two methods of displaying animated GIFs in Liberty BASIC. One is to use an embedded ATL control and the other is to use GDIPlus. The ATL method is I think quite well documented elsewhere; for example you can download AnimGifs.zip from Gordon Sweet's site here (I can't give any personal endorsement of the quality of this code).

The GDIPlus method gives you more control, but it involves a lot more code. I've listed a program below to demonstrate it; it's LBB-only because it uses arrays of structures, which are not supported in LB 4:

Code:
    nomainwin
    MaxFrames = 1000
    global MaxFrames
    
    WindowWidth = 800
    WindowHeight = 600
    open "Animated GIFs" for graphics_nsb as #w
    #w "trapclose quit"
    hw = hwnd(#w)
    calldll #user32, "GetDC", hw as ulong, hdc as ulong
    do
      filedialog "Select an animated GIF", "*.gif", GIFfile$
      if GIFfile$ <> "" then call AnimatedGIF hdc, GIFfile$, 10
    loop until GIFfile$ = ""
    close #w
    end
    
sub quit h$
    close #h$
    end
end sub

' specify a duration in seconds or zero to play the animation once
sub AnimatedGIF hDC, filename$, duration
    open "gdiplus.dll" for dll as #gdiplus
    struct tSI, GdiplusVersion as long, DebugEventCallback as ulong, _
        SuppressBackgroundThread as long, SuppressExternalCodecs as long
    tSI.GdiplusVersion.struct = 1
    struct GDIP, l as struct
    calldll #gdiplus, "GdiplusStartup", GDIP as struct, tSI as struct, 0 as long, r as void
    
    struct graphics, p as ulong
    calldll #gdiplus, "GdipCreateFromHDC", hDC as ulong, graphics as struct, r as void
    calldll #gdiplus, "GdipSetSmoothingMode", graphics.p.struct as long, 2 as long, r as void
    
    l = len(filename$) + 1
    wide$ = space$(l * 2) + chr$(0)
    calldll #kernel32, "MultiByteToWideChar", 0 as long, 0 as long, _
        filename$ as ptr, -1 as long, wide$ as ptr, l as long, r as long

    struct image, p as ulong
    calldll #gdiplus, "GdipLoadImageFromFile", wide$ as ptr, image as struct, r as void
    if image.p.struct = 0 then notice "Couldn't open ";filename$ : exit sub
 
    struct dims, n as long
    calldll #gdiplus, "GdipImageGetFrameDimensionsCount", image.p.struct as ulong, _
        dims as struct, r as void
    if dims.n.struct > MaxFrames then notice "Too many frames: increase MaxFrames" : exit sub

    struct dimIDs(MaxFrames), a as long, b as long, c as long, d as long
    calldll #gdiplus, "GdipImageGetFrameDimensionsList", image.p.struct as ulong, _
        dimIDs(0) as struct, dims.n.struct as long, r as void
        
    struct frames, n as long    
    calldll #gdiplus, "GdipImageGetFrameCount", image.p.struct as ulong, _
        dimIDs(0) as struct, frames as struct, r as void
    if frames.n.struct > MaxFrames then notice "Too many frames: increase MaxFrames" : exit sub
 
    PropertyTagFrameDelay = hexdec("5100")
    struct psize, n as long
    calldll #gdiplus, "GdipGetPropertyItemSize", image.p.struct as ulong, _
        PropertyTagFrameDelay as long, psize as struct, r as void
    if (psize.n.struct / 4) > MaxFrames then notice "Too many frames: increase MaxFrames" : exit sub
    struct PropItem(MaxFrames), delay as long
        
    calldll #gdiplus, "GdipGetPropertyItem", image.p.struct as ulong, _
        PropertyTagFrameDelay as long, psize.n.struct as long, _
        PropItem(0) as struct, r as void
 
    struct xs, n as long
    struct ys, n as long
    calldll #gdiplus, "GdipGetImageWidth", image.p.struct as ulong, xs as struct, r as void
    calldll #gdiplus, "GdipGetImageHeight", image.p.struct as ulong, ys as struct, r as void    
    xsize = xs.n.struct
    ysize = ys.n.struct 

    if xsize > WindowWidth  then ysize *= WindowWidth / xsize  : xsize = WindowWidth
    IF ysize > WindowHeight then xsize *= WindowHeight / ysize : ysize = WindowHeight
 
    xpos = (WindowWidth - xsize) / 2
    ypos = (WindowHeight - ysize) / 2

    endtime = time$("ms") + duration * 1000
    do
      for frame = 0 to frames.n.struct - 1 
        calldll #gdiplus, "GdipImageSelectActiveFrame", image.p.struct as ulong, _
            dimIDs(0) as struct, frame as long, r as void
        #w "cls"
        calldll #gdiplus, "GdipDrawImageRectI", graphics.p.struct as ulong, _
            image.p.struct as ulong, xpos as long, ypos as long, _
            xsize as long, ysize as long, r as void
        delay = PropItem(frame+4).delay.struct
        if delay = 0 then delay = 8
        timer delay * 10, [animate]
        wait
[animate]
        timer 0
        scan
      next frame
    loop until time$("ms") >= endtime
 
    calldll #gdiplus, "GdipDisposeImage", image.p.struct as ulong, r as void
    calldll #gdiplus, "GdipDeleteGraphics", graphics.p.struct as ulong, r as void
    calldll #gdiplus, "GdiplusShutdown", GDIP.l.struct as ulong, r as void
    close #gdiplus
end sub 

You can specify that the GIF animates just once, or repeats the animation for a specified period in seconds. Note that GIFs with a frame period less than about 10 milliseconds will animate more slowly than they should using this code, because of limitations of the Liberty BASIC timer (however such a fast animation is pointless because the eye/brain can't follow it).

Richard.
« Last Edit: Oct 16th, 2016, 11:34am by Richard Russell » User IP Logged

Rod
Full Member
ImageImageImage


member is offline

Avatar




PM

Gender: Male
Posts: 110
xx Re: Displaying animated GIFs with LBB?
« Reply #2 on: Oct 16th, 2016, 7:20pm »

The standard ATL code has been proved to work for .gif files on a variety of systems. So the question is, is this a normal .gif file? or are there PC specific constraints that stop the gif from playing.

So it will be interesting to hear if Gordon's code runs for you.

Share the culprit .gif if not.
User IP Logged

Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 1348
xx Re: Displaying animated GIFs with LBB?
« Reply #3 on: Oct 17th, 2016, 10:27am »

on Oct 16th, 2016, 7:20pm, Rod wrote:
The standard ATL code has been proved to work for .gif files on a variety of systems.

I would expect it to work, but the GDIPlus code is a lot more flexible. Here are some of the things it can do which the ATL control can't:
  • Since it uses a standard graphics window or graphicbox, you can draw over the GIF, add text to the GIF, save the GIF to a BMP file, scroll the window etc.

  • You can gather information about the GIF, such as image dimensions, number of frames, duration of each frame etc.

  • You can control the animation, for example display only some of the frames, or animate it backwards, or animate it at a different speed, or repeat it only a certain number of times etc.
Richard.
User IP Logged

Rod
Full Member
ImageImageImage


member is offline

Avatar




PM

Gender: Male
Posts: 110
xx Re: Displaying animated GIFs with LBB?
« Reply #4 on: Oct 17th, 2016, 12:23pm »

Yes I see it is much more flexible, but the gif should display with the ATL code, so interested to so what Harbinger discovers.
User IP Logged

Harbinger
New Member
Image


member is offline

Avatar




PM

Gender: Male
Posts: 2
xx Re: Displaying animated GIFs with LBB?
« Reply #5 on: Oct 23rd, 2016, 04:30am »

OK now we're talkin'! It worked on most GIFs, but a few of them weren't displaying correctly. I will narrow down what the difference to see if I can find out why the problem is there...

Now in order to integrate this code into my own program, I need to know what everything does. Can you over-comment the same code, and explain what we're doing with each line (or at least the important ones)? You said we have a lot more flexibility, so i'd like to know what I can exploit to give the user more options.
For my purposes, for example, all GIFs will be DISPLAYED at 25 frames per second. But i'd like to be able to alert the user what the GIVEN framerate is, for the GIF in the preview. Can that be determined? (We'll go with the starting fps since that can be different within each frame.)

Also i'm trying to figure out a way to show the transparency color (index= 0, rgb= "000000") for my bitmaps by recoloring that hue in each frame. Any ideas for GIFs? None of the GIFs or bitmaps have an alpha channel...

Other than those questions, the thing worked like a charm, but I just need to know what does what... cool
User IP Logged

Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 1348
xx Re: Displaying animated GIFs with LBB?
« Reply #6 on: Oct 23rd, 2016, 09:38am »

on Oct 23rd, 2016, 04:30am, Harbinger wrote:
But i'd like to be able to alert the user what the GIVEN framerate is, for the GIF in the preview. Can that be determined?

Yes. The GdipGetPropertyItem API call, with the PropertyTagFrameDelay parameter, retrieves the duration (in centiseconds) for each frame and stores them in the PropItem() array of structures:

Code:
    struct PropItem(MaxFrames), delay as long
        
    calldll #gdiplus, "GdipGetPropertyItem", image.p.struct as ulong, _
        PropertyTagFrameDelay as long, psize.n.struct as long, _
        PropItem(0) as struct, r as void 

There's a 16-byte header that has to be skipped so to find the duration of the first frame you can do:

Code:
duration = PropItem(4).delay.struct 

(my code makes the assumption that the array immediately follows the header, and that's not documented at MSDN so may be unreliable).

Quote:
We'll go with the starting fps since that can be different within each frame.

Generally that makes sense but be careful that there are some animated GIFs in which the first frame is a 'title' and is displayed for a much longer period than the rest. In that case the last frame would be a better guess at the 'normal' rate.

Quote:
Also i'm trying to figure out a way to show the transparency color (index= 0, rgb= "000000") for my bitmaps by recoloring that hue in each frame. Any ideas for GIFs?

That's easy. The GdipDrawImageRectI function doesn't draw transparent regions at all, which is why there is a CLS immediately preceding it in the code. If you replace that CLS with a FILL you can set the color of the 'transparent' regions to anything you like.

Richard.
User IP Logged

Pages: 1  Notify Send Topic Print
« Previous Topic | Next Topic »

| |

This forum powered for FREE by Conforums ©
Terms of Service | Privacy Policy | Conforums Support | Parental Controls