Dont throw EncodingFoundException unless asked to. Should remove the occassional...
[beagle.git] / Filters / FilterGif.cs
blob5216cad836847f3c3b12f97e63b379f938decacb
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 static public bool Debug = false;
53 public FilterGif () : base ()
55 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("image/gif"));
58 protected override void PullImageProperties ()
60 try {
61 /* Parse the GIF Header to get the version and overall size */
62 byte [] data = new byte [13];
63 Stream.Read (data, 0, data.Length);
65 if (data [0] != 'G' || data [1] != 'I' || data [2] != 'F') {
66 Logger.Log.Debug ("File is not a GIF file!");
67 Error ();
68 return;
71 char [] gif_version = { (char) data [3], (char) data [4], (char) data [5] };
73 AddProperty (Beagle.Property.NewUnsearched ("gif:version", new string (gif_version)));
75 ushort width = EndianConverter.ToUInt16 (data, 6, true);
76 ushort height = EndianConverter.ToUInt16 (data, 8, true);
78 Width = width;
79 Height = height;
82 * Everything from here onwards is for parsing the GIF Stream
83 * and extracting comments and plaintext and working out how
84 * many frames there are and how many times they are supposed
85 * to loop.
88 GifBytes gb;
89 int b, num_frames = 0, ct_size;
91 if ((data [10] & 0x80) == 0x80) {
92 /* A Global Color Table exists */
93 ct_size = (int) (3 * Math.Pow(2, (data[10] & 0x07) + 1));
95 if (Debug)
96 Logger.Log.Debug ("ct_size: " + ct_size);
98 Stream.Seek (ct_size, SeekOrigin.Current);
101 while ((gb = (GifBytes) Stream.ReadByte ()) != GifBytes.Trailer
102 && (int) gb != -1) {
104 switch (gb) {
105 case GifBytes.ImageBlockSeparator:
106 num_frames++;
108 if (Debug)
109 Logger.Log.Debug ("Start of Image Block : " + Stream.Position);
111 Stream.Seek (8, SeekOrigin.Current);
112 b = Stream.ReadByte ();
114 if ((b & 0x80) == 0x80) {
115 /* A Local Color Table exists */
117 ct_size = (int) (3 * Math.Pow(2, (b & 0x07) + 1));
119 if (Debug) {
120 Logger.Log.Debug ("-- Image Block has local color table");
121 Logger.Log.Debug ("ct_size: " + ct_size);
124 Stream.Seek (ct_size, SeekOrigin.Current);
127 Stream.ReadByte ();
128 while ((b = Stream.ReadByte ()) != 0x0) {
129 if (Debug)
130 Logger.Log.Debug ("-- Image Data Block size: " + b + " pos: " + Stream.Position);
132 if (b == -1) {
133 Logger.Log.Warn ("Invalid Data Block size");
134 Error ();
135 return;
138 Stream.Seek (b, SeekOrigin.Current);
141 if (Debug)
142 Logger.Log.Debug ("-- Image Block end: " + Stream.Position);
143 break;
145 case GifBytes.BlockIntroducer:
146 if (Debug)
147 Logger.Log.Debug ("Start of Extension : " + Stream.Position);
148 break;
150 case GifBytes.GraphicControlExtension:
151 if (Debug)
152 Logger.Log.Debug ("-- Graphic Control Extension : " + Stream.Position);
154 Stream.Seek (6, SeekOrigin.Current);
155 break;
157 case GifBytes.PlaintextExtension:
158 if (Debug)
159 Logger.Log.Debug ("Plaintext Extension: " + Stream.Position);
161 Stream.Seek (13, SeekOrigin.Current);
163 while ((b = Stream.ReadByte ()) != 0x0) {
164 if (Debug)
165 Logger.Log.Debug ("-- Plaintext Data Block size: " + b + " pos: " + Stream.Position);
167 if (b == -1) {
168 Logger.Log.Warn ("Invalid Plaintext Data Block size!");
169 Error ();
170 return;
173 char [] cbuffer = new char [b];
175 for (int i = 0; i < b; i++)
176 cbuffer [i] = (char) Stream.ReadByte ();
178 AppendText (new string (cbuffer));
180 if (Debug)
181 Logger.Log.Debug ("-- Plaintext Data: " + new string(cbuffer));
184 if (Debug)
185 Logger.Log.Debug ("-- Plaintext Extension End: " + Stream.Position);
186 break;
188 case GifBytes.CommentExtension:
189 if (Debug)
190 Logger.Log.Debug ("Comment Extension: " + Stream.Position);
192 while ((b = Stream.ReadByte ()) != 0x0) {
193 if (Debug)
194 Logger.Log.Debug ("-- Comment Data Block size: " + b + " pos: " + Stream.Position);
196 if (b == -1) {
197 Logger.Log.Warn ("Invalid Comment Data Block size!");
198 Error ();
199 return;
202 char [] cbuffer = new char [b];
204 for (int i = 0; i < b; i++) {
205 cbuffer[i] = (char) Stream.ReadByte ();
208 AppendText (new string (cbuffer));
210 if (Debug)
211 Logger.Log.Debug ("-- Comment Data: " + new string(cbuffer));
214 if (Debug)
215 Logger.Log.Debug ("-- Comment Extension End: " + Stream.Position);
216 break;
218 case GifBytes.ApplicationExtension:
219 if (Debug)
220 Logger.Log.Debug ("Application Extension: " + Stream.Position);
222 Stream.ReadByte ();
224 char [] cbuffer = new char [11];
225 for (int i = 0; i < 11; i++) {
226 cbuffer [i] = (char) Stream.ReadByte ();
229 string application = new string (cbuffer);
231 if (application == "NETSCAPE2.0") {
232 if (Debug)
233 Logger.Log.Debug ("-- Application: 'NETSCAPE2.0'>");
235 Stream.ReadByte ();
236 Stream.ReadByte ();
238 b = Stream.ReadByte();
240 if (b == 0)
241 AddProperty (Beagle.Property.NewUnsearched ("gif:loopcount", "infinite"));
242 else
243 AddProperty (Beagle.Property.NewUnsearched ("gif:loopcount", b));
245 Stream.ReadByte();
246 } else {
247 //unknown extension...
248 while ((b = Stream.ReadByte ()) != 0x0) {
249 if (Debug)
250 Logger.Log.Debug ("-- Application Data Block size: " + b + " pos: " + Stream.Position);
252 if (b == -1) {
253 Logger.Log.Warn ("Invalid Application Data Block size!");
254 Error ();
255 return;
258 Stream.Seek (b, SeekOrigin.Current);
262 if (Debug)
263 Logger.Log.Debug ("-- Application Extension End: " + Stream.Position);
264 break;
266 default:
267 break;
271 if (Debug && gb == GifBytes.Trailer)
272 Logger.Log.Debug ("Trailer marker: " + Stream.Position);
274 // We got zero frames, this isn't actually a valid GIF file.
275 if (num_frames == 0) {
276 Logger.Log.Debug ("File doesn't contain any GIF frames");
277 Error ();
278 return;
281 AddProperty (Beagle.Property.NewUnsearched ("gif:numframes", num_frames));
282 } catch (Exception e) {
283 if (Debug)
284 Logger.Log.Debug ("-- Exception: {0} - {1}", Stream.Position, e);
285 Error ();