GIFReadWriter and Animated GIFs

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

GIFReadWriter and Animated GIFs

darth-cheney
Hello all,

Please excuse the length of this email.

A week or two ago I discovered that the GIF implementation in Pharo (and possibly Squeak?) is incomplete. This has two side effects:
1) Not all GIF data will load correctly;
2) There is for now no way to display animated GIFs.

It looks like the corresponding classes have not been updated since the 90s.

But fear not! I've been working on a solution, and need the community's feedback and advice.

# The Problem with GIFs #
One of the issues here is that GIF files can (and do) contain multiple images inside of them. The root header will supply things like a "screen size" in which these nested images should be displayed. That also means that each nested image does not have to have the same dimensions as the parent object -- in fact, most are offset somewhere inside of the "screen."

Additionally, each nested image will contain information about how it should be handled when animating. This is a crucial point. In many cases images are just updates of a small area that should be applied to the previous image in the set. GIFs call this attribute the "disposal," and this information is contained in a packed byte.

Both GIFReadWriter and AnimatedGIFReadWriter have intentionally skipped/ignored the bits/bytes that store and keep track of these things. GIFReadWriter on its own will only read the first Form and does not store information about disposal, offsets, etc. These classes are not reading all the information we need to display GIFs!
 
# My Solution #
The attached changes file includes some preliminary updates to the GIFReadWriter class. Now when each nested image is read, it will be loaded into a collection called "frames" as a (new -- see attached package file) AnimatedImageFrame. Instances of this new class will store the disposal symbol, offset, and form for each nested image in the file.

I have also created an AnimatedImageMorph which reads AnimatedImageFrame objects and cycles them based on the disposal re-drawing rules.
 
# Trying This Out #
To try this out, first load the attached changes file and the ST file.
 
You'll need a FileReference to a gif file, so when you have one execute the following:

```smalltalk
file := "your gif filereference here"
img := AnimatedImageMorph fromGIFReader: (AnimatedGIFReadWriter formsFromStream: file readStream).
img openInWorld.
```

# Issues #
Not all GIF images work. This has to do with my implementation of the disposal (redrawing) rules for each frame. I'm still experimenting.

I believe AnimatedGIFReadWriter should be deprecated and all appropriate functionality should be put into GIFReadWriter. If you all agree, I will make several changes to GIFReadWriter that I think will be helpful / necessary.

AnimatedImageMorph is also incomplete. I'm not sure if I should subclass ImageMorph for this or not.

# Your Feedback #
If you disagree with any point of this architecture, please let me know. Also if you come across GIFs that do not animate or display properly, send them my way please!

--
Eric

Images-Animated.st (6K) Download Attachment
GIFReadWriter.EricGade.cs (7K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: GIFReadWriter and Animated GIFs

Sven Van Caekenberghe-2
Hi Eric,

I can't speak about the Morph related aspects, not my area of expertise.

The other aspects, about the actual read/writer, all sound reasonable.

It would be very good if someone contributed to improve the quality of GIFReadWriter, thanks for doing this !

One remark though, I think that your changes are based off Pharo 6. That is a problem because GIFReadWriter underwent a couple of changes in relation to stream/file handling. I see some small conflicts in #readHeader, nothing major.

I also assume the transcript printing will be removed eventually.

Normally development takes place in Pharo 7 with an option to back port to Pharo 6.1 if it is a very important change. These kind of discussions also normally happen on the pharo-dev mailing list.

Thanks again and please continue.

Sven

PS: maybe you can find a GIF test suite somewhere like there exists one for PNG (https://pharo.manuscript.com/f/cases/21927/Figure-out-why-PNGReadWriter-does-not-pass-a-full-test-suite and https://github.com/DraagrenKirneh/PngSuiteExplorer).

> On 23 May 2018, at 21:08, Eric Gade <[hidden email]> wrote:
>
> Hello all,
>
> Please excuse the length of this email.
>
> A week or two ago I discovered that the GIF implementation in Pharo (and possibly Squeak?) is incomplete. This has two side effects:
> 1) Not all GIF data will load correctly;
> 2) There is for now no way to display animated GIFs.
>
> It looks like the corresponding classes have not been updated since the 90s.
>
> But fear not! I've been working on a solution, and need the community's feedback and advice.
>
> # The Problem with GIFs #
> One of the issues here is that GIF files can (and do) contain multiple images inside of them. The root header will supply things like a "screen size" in which these nested images should be displayed. That also means that each nested image does not have to have the same dimensions as the parent object -- in fact, most are offset somewhere inside of the "screen."
>
> Additionally, each nested image will contain information about how it should be handled when animating. This is a crucial point. In many cases images are just updates of a small area that should be applied to the previous image in the set. GIFs call this attribute the "disposal," and this information is contained in a packed byte.
>
> Both GIFReadWriter and AnimatedGIFReadWriter have intentionally skipped/ignored the bits/bytes that store and keep track of these things. GIFReadWriter on its own will only read the first Form and does not store information about disposal, offsets, etc. These classes are not reading all the information we need to display GIFs!
>  
> # My Solution #
> The attached changes file includes some preliminary updates to the GIFReadWriter class. Now when each nested image is read, it will be loaded into a collection called "frames" as a (new -- see attached package file) AnimatedImageFrame. Instances of this new class will store the disposal symbol, offset, and form for each nested image in the file.
>
> I have also created an AnimatedImageMorph which reads AnimatedImageFrame objects and cycles them based on the disposal re-drawing rules.
>  
> # Trying This Out #
> To try this out, first load the attached changes file and the ST file.
>  
> You'll need a FileReference to a gif file, so when you have one execute the following:
>
> ```smalltalk
> file := "your gif filereference here"
> img := AnimatedImageMorph fromGIFReader: (AnimatedGIFReadWriter formsFromStream: file readStream).
> img openInWorld.
> ```
>
> # Issues #
> Not all GIF images work. This has to do with my implementation of the disposal (redrawing) rules for each frame. I'm still experimenting.
>
> I believe AnimatedGIFReadWriter should be deprecated and all appropriate functionality should be put into GIFReadWriter. If you all agree, I will make several changes to GIFReadWriter that I think will be helpful / necessary.
>
> AnimatedImageMorph is also incomplete. I'm not sure if I should subclass ImageMorph for this or not.
>
> # Your Feedback #
> If you disagree with any point of this architecture, please let me know. Also if you come across GIFs that do not animate or display properly, send them my way please!
>
> --
> Eric
> <Images-Animated.st><GIFReadWriter.EricGade.cs>


Reply | Threaded
Open this post in threaded view
|

Re: GIFReadWriter and Animated GIFs

darth-cheney
Thanks, Sven. I'll switch over to Pharo 7a and continue my efforts there. When I have something worth a damn I'll submit a PR according to the new contribution protocol.

On Wed, May 23, 2018 at 4:44 PM, Sven Van Caekenberghe <[hidden email]> wrote:
Hi Eric,

I can't speak about the Morph related aspects, not my area of expertise.

The other aspects, about the actual read/writer, all sound reasonable.

It would be very good if someone contributed to improve the quality of GIFReadWriter, thanks for doing this !

One remark though, I think that your changes are based off Pharo 6. That is a problem because GIFReadWriter underwent a couple of changes in relation to stream/file handling. I see some small conflicts in #readHeader, nothing major.

I also assume the transcript printing will be removed eventually.

Normally development takes place in Pharo 7 with an option to back port to Pharo 6.1 if it is a very important change. These kind of discussions also normally happen on the pharo-dev mailing list.

Thanks again and please continue.

Sven

PS: maybe you can find a GIF test suite somewhere like there exists one for PNG (https://pharo.manuscript.com/f/cases/21927/Figure-out-why-PNGReadWriter-does-not-pass-a-full-test-suite and https://github.com/DraagrenKirneh/PngSuiteExplorer).

> On 23 May 2018, at 21:08, Eric Gade <[hidden email]> wrote:
>
> Hello all,
>
> Please excuse the length of this email.
>
> A week or two ago I discovered that the GIF implementation in Pharo (and possibly Squeak?) is incomplete. This has two side effects:
> 1) Not all GIF data will load correctly;
> 2) There is for now no way to display animated GIFs.
>
> It looks like the corresponding classes have not been updated since the 90s.
>
> But fear not! I've been working on a solution, and need the community's feedback and advice.
>
> # The Problem with GIFs #
> One of the issues here is that GIF files can (and do) contain multiple images inside of them. The root header will supply things like a "screen size" in which these nested images should be displayed. That also means that each nested image does not have to have the same dimensions as the parent object -- in fact, most are offset somewhere inside of the "screen."
>
> Additionally, each nested image will contain information about how it should be handled when animating. This is a crucial point. In many cases images are just updates of a small area that should be applied to the previous image in the set. GIFs call this attribute the "disposal," and this information is contained in a packed byte.
>
> Both GIFReadWriter and AnimatedGIFReadWriter have intentionally skipped/ignored the bits/bytes that store and keep track of these things. GIFReadWriter on its own will only read the first Form and does not store information about disposal, offsets, etc. These classes are not reading all the information we need to display GIFs!
>   
> # My Solution #
> The attached changes file includes some preliminary updates to the GIFReadWriter class. Now when each nested image is read, it will be loaded into a collection called "frames" as a (new -- see attached package file) AnimatedImageFrame. Instances of this new class will store the disposal symbol, offset, and form for each nested image in the file.
>
> I have also created an AnimatedImageMorph which reads AnimatedImageFrame objects and cycles them based on the disposal re-drawing rules.
>   
> # Trying This Out #
> To try this out, first load the attached changes file and the ST file.
>   
> You'll need a FileReference to a gif file, so when you have one execute the following:
>
> ```smalltalk
> file := "your gif filereference here"
> img := AnimatedImageMorph fromGIFReader: (AnimatedGIFReadWriter formsFromStream: file readStream).
> img openInWorld.
> ```
>
> # Issues #
> Not all GIF images work. This has to do with my implementation of the disposal (redrawing) rules for each frame. I'm still experimenting.
>
> I believe AnimatedGIFReadWriter should be deprecated and all appropriate functionality should be put into GIFReadWriter. If you all agree, I will make several changes to GIFReadWriter that I think will be helpful / necessary.
>
> AnimatedImageMorph is also incomplete. I'm not sure if I should subclass ImageMorph for this or not.
>
> # Your Feedback #
> If you disagree with any point of this architecture, please let me know. Also if you come across GIFs that do not animate or display properly, send them my way please!
>
> --
> Eric
> <Images-Animated.st><GIFReadWriter.EricGade.cs>





--
Eric
Reply | Threaded
Open this post in threaded view
|

Re: GIFReadWriter and Animated GIFs

Guillermo Polito
Big thanks :) If you have any question regarding the stream changes, go on

On Wed, May 23, 2018 at 10:52 PM, Eric Gade <[hidden email]> wrote:
Thanks, Sven. I'll switch over to Pharo 7a and continue my efforts there. When I have something worth a damn I'll submit a PR according to the new contribution protocol.

On Wed, May 23, 2018 at 4:44 PM, Sven Van Caekenberghe <[hidden email]> wrote:
Hi Eric,

I can't speak about the Morph related aspects, not my area of expertise.

The other aspects, about the actual read/writer, all sound reasonable.

It would be very good if someone contributed to improve the quality of GIFReadWriter, thanks for doing this !

One remark though, I think that your changes are based off Pharo 6. That is a problem because GIFReadWriter underwent a couple of changes in relation to stream/file handling. I see some small conflicts in #readHeader, nothing major.

I also assume the transcript printing will be removed eventually.

Normally development takes place in Pharo 7 with an option to back port to Pharo 6.1 if it is a very important change. These kind of discussions also normally happen on the pharo-dev mailing list.

Thanks again and please continue.

Sven

PS: maybe you can find a GIF test suite somewhere like there exists one for PNG (https://pharo.manuscript.com/f/cases/21927/Figure-out-why-PNGReadWriter-does-not-pass-a-full-test-suite and https://github.com/DraagrenKirneh/PngSuiteExplorer).

> On 23 May 2018, at 21:08, Eric Gade <[hidden email]> wrote:
>
> Hello all,
>
> Please excuse the length of this email.
>
> A week or two ago I discovered that the GIF implementation in Pharo (and possibly Squeak?) is incomplete. This has two side effects:
> 1) Not all GIF data will load correctly;
> 2) There is for now no way to display animated GIFs.
>
> It looks like the corresponding classes have not been updated since the 90s.
>
> But fear not! I've been working on a solution, and need the community's feedback and advice.
>
> # The Problem with GIFs #
> One of the issues here is that GIF files can (and do) contain multiple images inside of them. The root header will supply things like a "screen size" in which these nested images should be displayed. That also means that each nested image does not have to have the same dimensions as the parent object -- in fact, most are offset somewhere inside of the "screen."
>
> Additionally, each nested image will contain information about how it should be handled when animating. This is a crucial point. In many cases images are just updates of a small area that should be applied to the previous image in the set. GIFs call this attribute the "disposal," and this information is contained in a packed byte.
>
> Both GIFReadWriter and AnimatedGIFReadWriter have intentionally skipped/ignored the bits/bytes that store and keep track of these things. GIFReadWriter on its own will only read the first Form and does not store information about disposal, offsets, etc. These classes are not reading all the information we need to display GIFs!
>   
> # My Solution #
> The attached changes file includes some preliminary updates to the GIFReadWriter class. Now when each nested image is read, it will be loaded into a collection called "frames" as a (new -- see attached package file) AnimatedImageFrame. Instances of this new class will store the disposal symbol, offset, and form for each nested image in the file.
>
> I have also created an AnimatedImageMorph which reads AnimatedImageFrame objects and cycles them based on the disposal re-drawing rules.
>   
> # Trying This Out #
> To try this out, first load the attached changes file and the ST file.
>   
> You'll need a FileReference to a gif file, so when you have one execute the following:
>
> ```smalltalk
> file := "your gif filereference here"
> img := AnimatedImageMorph fromGIFReader: (AnimatedGIFReadWriter formsFromStream: file readStream).
> img openInWorld.
> ```
>
> # Issues #
> Not all GIF images work. This has to do with my implementation of the disposal (redrawing) rules for each frame. I'm still experimenting.
>
> I believe AnimatedGIFReadWriter should be deprecated and all appropriate functionality should be put into GIFReadWriter. If you all agree, I will make several changes to GIFReadWriter that I think will be helpful / necessary.
>
> AnimatedImageMorph is also incomplete. I'm not sure if I should subclass ImageMorph for this or not.
>
> # Your Feedback #
> If you disagree with any point of this architecture, please let me know. Also if you come across GIFs that do not animate or display properly, send them my way please!
>
> --
> Eric
> <Images-Animated.st><GIFReadWriter.EricGade.cs>





--
Eric



--

   

Guille Polito

Research Engineer

Centre de Recherche en Informatique, Signal et Automatique de Lille

CRIStAL - UMR 9189

French National Center for Scientific Research - http://www.cnrs.fr


Web: http://guillep.github.io

Phone: +33 06 52 70 66 13