Saturday, May 15, 2010

Animated Gifs Everywhere

Its not that LWUIT doesn't support animated GIF's as much as the underlying implementation doesn't support them. MIDP doesn't provide any API's to extract the frames of the animated GIF's and get any indication of when to repaint them.
The solution would seem to parse animated GIF's ourselves and paint them ourselves, this isn't trivial since the animated GIF compression and painting logic is rather complex. However, Ugo Chirico seems to have done just that quite a while back!
His image class allows loading and displaying an animated GIF within LWUIT and works for many animated GIF's. It probably won't become a part of LWUIT in part due to copyright issues, but I have made some changes to the way he chose to integrate into LWUIT so you don't actually need to change LWUIT in order to integrate with his code.
Furthermore, when using my modified LWUIT implementation animated GIF's will be automatically detected and "just work" even within the HTML component and other elaborate use cases in LWUIT.
I achieved this by overriding the LWUIT implementation (the VKB version) and all that's necessary to integrate it is to invoke AnimatedGifFactory.install(); before the Display.init() call.

You can get my code from the vprise directory in the LWUIT incubator project, the project includes a small test application within as well.

This can serve as a template to anyone wishing to add additional image support to LWUIT, there are several tricks I used to achieve this:

  • Image loading requires detecting the image type from the stream, however once I started reading the stream I will need to handle all image types.... To solve this I added BufferedInputStream which guarantees that mark()/reset() would work on the stream and thus I'm able to restore the input stream to its original state in case the image is not a GIF!
  • I return an internal "native" image, but I don't use MIDP at any point. While I haven't tested it I bet my code works well on Android/RIM since I only use LWUIT logic internally.
    One would obviously need to modify the classes from which I derive to the appropriate Android/RIM implementations for this to work...
  • LWUIT animation calls update the state of the GIF, Ugo did this perfectly and I just used the implementation to map directly to his code.

10 comments:

  1. This code requires the latest LWUIT from SVN to work properly.

    ReplyDelete
  2. Hi Shai, thank you for your taking my AnimatedGif class in LWUIT.
    I'm looking for your implementation in SVN but I was not able to find it.
    Where is it?

    ReplyDelete
  3. Hi Ugo,
    its not in the LWUIT SVN since it won't pass the licensing threshold we need for code (might violate some rights e.g. yours).
    You need to sign the SCA for one and since you based the code on 3rd party code the SCA pretty much says you can't submit it to us anyway ;-)

    I did place the code in the lwuit-incubator project which has 3rd party contributor code.

    ReplyDelete
  4. Hello Shai

    I was just trying out the AnimatedGifImplementation from the incubator projects SVN directory. This gives an error when used with LWUIT 1.5

    AnimatedGifImplementation extends VKBImplementation which doesn't exist in LWUIT 1.5 and AnimatedGifFactory extends VKBImplementationFactory which is deprecated. Can you please guide me as to what are the changes that need to be made to make the AnimatedGifImplementation work?

    Thanks in advance.

    ReplyDelete
  5. Just change it to derive from GameCanvasImplementation and the default factory, both of these now incorporate the functionality of the old VKBImplementation.

    ReplyDelete
  6. As far as I recall my implementation it should work with any arbitrary input stream or data.

    ReplyDelete
  7. When you use the implementation I provided in the incubator you just create an Image object using the standard image create methods. A Label/Button will accept that image and animate it just like you would expect normally.
    LWUIT has builtin support for pluggability and animation.

    ReplyDelete
  8. hi shai,

    your work is great but how to implement it in blackberry?

    i'm using LWUIT BB 1.5 pre4.7 and got "nullpointer" error when i call Image.createImage("/file.gif")

    I have replaced GameCanvasImplementation and VKBImplementation with BlackberryImplementation because i can not find the GameCanvasImplementation in LWUIT BB 1.5 pre4.7 jar. So the code snippet looks like this:

    import com.sun.lwuit.impl.blackberry.BlackberryImplementation;

    public class AnimatedGIFImplementation extends BlackberryImplementation

    and the AnimatedGifFactory looks like this:

    public class AnimatedGifFactory extends ImplementationFactory

    because I can't find specific factory for BB implementation.

    ReplyDelete
  9. Blackberry is pretty different and you would need to implement two versions for it the touch and standard version.
    The factory is in the same place for the blackberry implementation it just initializes the blackberry code instead of MIDP, we don't replace it normally.

    ReplyDelete
  10. Hi Shai. I know this GIF issue is a bit aged but my code is a bit challenging. When my LWUIT app is launching, I use J2ME canvas to show my splash screen. First issue is that I want to use an animated GIF I have made, together with the splash screen(As for now, I'm using a png image). Second issue is that, so as to avoid potential memory leaks, I've taken to using mostly dialogs rather than having forms for everything. That said, can you help me show a GIF image in a dialog that appears when the app is relaying or recieving data eg from a facebook status of a user?

    ReplyDelete