Forgot to bump FSQ version. Weekend syndrome.
[beagle.git] / Filters / FilterGif.cs
blob1abdcf63e7b4e511293a4bc1fb35826ad5103e19
1 //
2 // FilterGif.cs
3 //
4 // Copyright (C) 2006 Alexander Macdonald <alex@alexmac.cc>
5 //
7 //
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.
27 using System;
28 using System.IO;
29 using System.Text;
31 using Beagle.Util;
32 using Beagle.Daemon;
34 namespace Beagle.Filters {
36 public class FilterGif : FilterImage {
38 enum GifBytes {
39 Trailer = 0x3b,
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 ()
58 try {
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)));
70 Width = width;
71 Height = height;
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
77 * to loop.
80 GifBytes gb;
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) {
91 switch (gb) {
92 case GifBytes.ImageBlockSeparator:
93 num_frames++;
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);
108 Stream.ReadByte ();
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);
115 break;
117 case GifBytes.BlockIntroducer:
118 //System.Console.WriteLine("Start of Extension : " + Stream.Position);
119 break;
121 case GifBytes.GraphicControlExtension:
122 //System.Console.WriteLine("-- Graphic Control Extension : " + Stream.Position);
123 Stream.Seek (6, SeekOrigin.Current);
124 break;
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);
143 break;
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);
161 break;
163 case GifBytes.ApplicationExtension:
164 //System.Console.WriteLine("Application Extension: " + Stream.Position);
166 Stream.ReadByte ();
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'>");
178 Stream.ReadByte ();
179 Stream.ReadByte ();
181 b = Stream.ReadByte();
183 if (b == 0)
184 AddProperty (Beagle.Property.NewUnsearched ("gif:loopcount", "infinite"));
185 else
186 AddProperty (Beagle.Property.NewUnsearched ("gif:loopcount", b));
188 Stream.ReadByte();
189 } else {
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);
197 break;
199 default:
200 break;
203 AddProperty (Beagle.Property.NewUnsearched ("gif:numframes", num_frames));
204 } catch (Exception) {
205 //System.Console.WriteLine("-- Exception! " + Stream.Position);
206 Error ();