Author |
Topic: Displaying animated GIFs with LBB? (Read 808 times) |
|
Harbinger
New Member
member is offline
Gender:
Posts: 2
|
|
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?
|
|
Logged
|
|
|
|
Richard Russell
Administrator
member is offline
Posts: 1348
|
|
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.
|
|
|
|
Rod
Full Member
member is offline
Gender:
Posts: 110
|
|
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.
|
|
Logged
|
|
|
|
Richard Russell
Administrator
member is offline
Posts: 1348
|
|
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.
|
|
Logged
|
|
|
|
Rod
Full Member
member is offline
Gender:
Posts: 110
|
|
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.
|
|
Logged
|
|
|
|
Harbinger
New Member
member is offline
Gender:
Posts: 2
|
|
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...
|
|
Logged
|
|
|
|
Richard Russell
Administrator
member is offline
Posts: 1348
|
|
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.
|
|
Logged
|
|
|
|
|