4 // Copyright (C) 2006 Alexander Macdonald <alex@alexmac.cc>
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
34 namespace Beagle
.Filters
{
36 public class FilterGif
: FilterImage
{
40 ImageBlockSeparator
= 0x2c,
42 BlockIntroducer
= 0x21,
43 BlockTerminator
= 0x00,
45 GraphicControlExtension
= 0xf9,
46 CommentExtension
= 0xfe,
47 PlaintextExtension
= 0x01,
48 ApplicationExtension
= 0xff
51 public FilterGif () : base ()
53 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("image/gif"));
56 protected override void PullImageProperties ()
59 /* Parse the GIF Header to get the version and overall size */
60 byte [] data
= new byte [13];
61 Stream
.Read (data
, 0, data
.Length
);
63 ushort width
= EndianConverter
.ToUInt16 (data
, 6, true);
64 ushort height
= EndianConverter
.ToUInt16 (data
, 8, true);
66 char [] gif_version
= { (char) data [3], (char) data [4], (char) data [5] }
;
68 AddProperty (Beagle
.Property
.NewUnsearched ("gif:version", new string (gif_version
)));
74 * Everything from here onwards is for parsing the GIF Stream
75 * and extracting comments and plaintext and working out how
76 * many frames there are and how many times they are supposed
81 int b
, num_frames
= 0, ct_size
;
83 if ((data
[10] & 0x80) == 0x80) {
84 /* A Global Color Table exists */
85 ct_size
= (int) (3 * Math
.Pow(2, (data
[10] & 0x07) + 1));
86 //System.Console.WriteLine("ct_size: " + ct_size);
87 Stream
.Seek (ct_size
, SeekOrigin
.Current
);
90 while ((gb
= (GifBytes
) Stream
.ReadByte ()) != GifBytes
.Trailer
) {
92 case GifBytes
.ImageBlockSeparator
:
95 //System.Console.WriteLine("Start of Image Block : " + Stream.Position);
97 Stream
.Seek (8, SeekOrigin
.Current
);
98 b
= Stream
.ReadByte ();
100 if ((b
& 0x80) == 0x80) {
101 /* A Local Color Table exists */
102 //System.Console.WriteLine("-- Image Block has local color table");
103 ct_size
= (int) (3 * Math
.Pow(2, (b
& 0x07) + 1));
104 //System.Console.WriteLine("ct_size: " + ct_size);
105 Stream
.Seek (ct_size
, SeekOrigin
.Current
);
109 while ((b
= Stream
.ReadByte ()) != 0x0) {
110 //System.Console.WriteLine("-- Image Data Block size: " + b + " pos: " + Stream.Position);
111 Stream
.Seek (b
, SeekOrigin
.Current
);
114 //System.Console.WriteLine("-- Image Block end: " + Stream.Position);
117 case GifBytes
.BlockIntroducer
:
118 //System.Console.WriteLine("Start of Extension : " + Stream.Position);
121 case GifBytes
.GraphicControlExtension
:
122 //System.Console.WriteLine("-- Graphic Control Extension : " + Stream.Position);
123 Stream
.Seek (6, SeekOrigin
.Current
);
126 case GifBytes
.PlaintextExtension
:
127 //System.Console.WriteLine("Plaintext Extension: " + Stream.Position);
129 Stream
.Seek (13, SeekOrigin
.Current
);
131 while ((b
= Stream
.ReadByte ()) != 0x0) {
132 //System.Console.WriteLine("-- Plaintext Data Block size: " + b + " pos: " + Stream.Position);
133 char [] cbuffer
= new char [b
];
135 for (int i
= 0; i
< b
; i
++)
136 cbuffer
[i
] = (char) Stream
.ReadByte ();
138 AppendText (new string (cbuffer
));
139 //System.Console.WriteLine("-- Plaintext Data: " + new string(cbuffer));
142 //System.Console.WriteLine("-- Plaintext Extension End: " + Stream.Position);
145 case GifBytes
.CommentExtension
:
146 //System.Console.WriteLine("Comment Extension: " + Stream.Position);
148 while ((b
= Stream
.ReadByte ()) != 0x0) {
149 //System.Console.WriteLine("-- Comment Data Block size: " + b + " pos: " + Stream.Position);
150 char [] cbuffer
= new char [b
];
152 for (int i
= 0; i
< b
; i
++) {
153 cbuffer
[i
] = (char) Stream
.ReadByte ();
156 AppendText (new string (cbuffer
));
157 //System.Console.WriteLine("-- Comment Data: " + new string(cbuffer));
160 //System.Console.WriteLine("-- Comment Extension End: " + Stream.Position);
163 case GifBytes
.ApplicationExtension
:
164 //System.Console.WriteLine("Application Extension: " + Stream.Position);
168 char [] cbuffer
= new char [11];
169 for (int i
= 0; i
< 11; i
++) {
170 cbuffer
[i
] = (char) Stream
.ReadByte ();
173 string application
= new string (cbuffer
);
175 if (application
== "NETSCAPE2.0") {
176 //System.Console.WriteLine("-- Application: 'NETSCAPE2.0'>");
181 b
= Stream
.ReadByte();
184 AddProperty (Beagle
.Property
.NewUnsearched ("gif:loopcount", "infinite"));
186 AddProperty (Beagle
.Property
.NewUnsearched ("gif:loopcount", b
));
190 //unknown extension...
191 while ((b
= Stream
.ReadByte ()) != 0x0) {
192 //System.Console.WriteLine("-- Application Data Block size: " + b + " pos: " + Stream.Position);
193 Stream
.Seek (b
, SeekOrigin
.Current
);
196 //System.Console.WriteLine("-- Application Extension End: " + Stream.Position);
203 AddProperty (Beagle
.Property
.NewUnsearched ("gif:numframes", num_frames
));
204 } catch (Exception
) {
205 //System.Console.WriteLine("-- Exception! " + Stream.Position);