* Filters/FilterPackage.cs, Filters/FilterRPM.cs,
[beagle.git] / Util / JpegHeader.cs
blobd8d122a77685a3d2d86fb3ce49808b6c4821fd93
1 namespace Beagle.Util {
3 public class JpegHeader {
4 public enum JpegMarker {
5 // The Following tags are listed as containing the content within the
6 // marker itself and the data is stored in the two bytes that would
7 // otherwise hold the length.
8 Tem = 0x01, // no length, ignore
9 Rst0 = 0xd0, // RstN used for resync, ignore
10 Rst1 = 0xd1,
11 Rst2 = 0xd2,
12 Rst3 = 0xd3,
13 Rst4 = 0xd4,
14 Rst5 = 0xd5,
15 Rst6 = 0xd6,
16 Rst7 = 0xd7,
18 Sof0 = 0xc0, // SOFn Start of frame 0-1 common
19 Sof1 = 0xc1,
20 Sof2 = 0xc2,
21 Sof3 = 0xc3,
23 Dht = 0xc4, // Define Huffman Table
25 Sof5 = 0xc5,
26 Sof6 = 0xc6,
27 Sof7 = 0xc7,
29 Jpg = 0xc8, // reserved
31 Sof9 = 0xc9,
32 Sof10 = 0xc10,
33 Sof11 = 0xc11,
34 Sof12 = 0xc12,
35 Sof13 = 0xc13,
36 Sof14 = 0xc14,
37 Sof15 = 0xc15,
39 // These tags all consist of a marker and then a length.
41 // These are the major structure tags.
42 Soi = 0xd8, // Start of Image
43 Eoi = 0xd9, // End of Image
44 Sos = 0xda, // Start of Scan
46 Dnl = 0xdc,
47 Dri = 0xdd, // Define restart interval
48 Dhp = 0xde,
49 Exp = 0xdf,
51 Dqt = 0xdb, // Define Quantization Table
53 // These are the app marker tags that contain the application metadata
54 // in its various forms.
55 App0 = 0xe0, // AppN Markers for application data
56 App1 = 0xe1,
57 App2 = 0xe2,
58 App3 = 0xe3,
59 App4 = 0xe4,
60 App5 = 0xe5,
61 App6 = 0xe6,
62 App7 = 0xe7,
63 App8 = 0xe8,
64 App9 = 0xe9,
65 App10 = 0xea,
66 App11 = 0xeb,
67 App12 = 0xec,
68 App13 = 0xed,
69 App14 = 0xee,
70 App15 = 0xef,
72 Jpg0 = 0xf0,
73 Jpg1 = 0xf1,
74 Jpg2 = 0xf2,
75 Jpg3 = 0xf3,
76 Jpg4 = 0xf4,
77 Jpg5 = 0xf5,
78 Jpg6 = 0xf6,
79 Jpg7 = 0xf7,
80 Jpg8 = 0xf8,
81 Jpg9 = 0xf9,
82 Jpg10 = 0xfa,
83 Jpg11 = 0xfb,
84 Jpg12 = 0xfc,
85 Jpg13 = 0xfd,
87 Com = 0xfe // Comment
90 public class Marker {
91 public Marker (JpegMarker type, byte [] data, long position)
93 this.Type = type;
94 this.Data = data;
95 this.Position = position;
98 public JpegMarker Type;
99 public byte [] Data;
100 public long Position;
103 public byte [] GetRawXmp ()
105 return this.GetRaw ("http://ns.adobe.com/xap/1.0/");
108 public byte [] GetRawExif ()
110 return this.GetRaw ("Exif");
112 public byte [] GetRawJfif ()
114 return this.GetRaw ("JFIF");
117 public byte [] GetJFIFComment ()
119 return this.GetRaw ("COM");
122 public byte [] GetRawIcc ()
124 return this.GetRaw ("ICC_PROFILE");
127 public byte [] GetRaw (string name)
129 Marker m = (Marker)app_marker_hash [name];
130 if (m != null)
131 return m.Data;
132 else
133 return null;
136 private void AddNamed (Marker m)
138 int j;
139 for (j = 0; j < m.Data.Length; j++) {
140 if (m.Data [j] == 0x00)
141 break;
144 string header = System.Text.Encoding.ASCII.GetString (m.Data, 0, j);
145 app_marker_hash [header] = m;
146 //System.Console.WriteLine (header);
149 System.Collections.Hashtable app_marker_hash = new System.Collections.Hashtable ();
150 System.Collections.ArrayList marker_list = new System.Collections.ArrayList ();
152 public JpegHeader (string filename)
154 //System.Console.WriteLine ("opening {0}", filename);
155 System.IO.FileStream stream = new System.IO.FileStream (filename, System.IO.FileMode.Open);
156 LoadFromStream (stream);
157 stream.Close ();
160 public JpegHeader (System.IO.Stream stream)
162 LoadFromStream (stream);
165 private void LoadFromStream (System.IO.Stream stream)
167 byte [] length_data = new byte [2];
169 if (stream.ReadByte () != 0xff || (JpegMarker)stream.ReadByte () != JpegMarker.Soi)
170 throw new System.Exception ("Invalid file Type, not a JPEG file");
172 bool at_image = false;
173 while (!at_image) {
174 int i = 0;
175 JpegMarker marker;
177 // 0xff can be used as padding between markers, ignore it all
178 // of it for now.
179 do {
180 marker = (JpegMarker)stream.ReadByte ();
181 i++;
182 } while (marker == (JpegMarker)0xff);
185 if (i < 2)
186 throw new System.Exception ("Invalid Marker");
188 long position = stream.Position - 1;
190 // FIXME use real byteswapping later
191 if (System.BitConverter.IsLittleEndian) {
192 length_data [1] = (byte)stream.ReadByte ();
193 length_data [0] = (byte)stream.ReadByte ();
194 } else {
195 length_data [0] = (byte)stream.ReadByte ();
196 length_data [1] = (byte)stream.ReadByte ();
199 ushort length = System.BitConverter.ToUInt16 (length_data, 0);
200 //System.Console.WriteLine ("Marker {0} Length = {1}", marker.ToString (), length);
202 if (length < 2)
203 throw new System.Exception ("Invalid Marker length");
205 length -= 2;
207 switch (marker) {
208 case JpegMarker.Com:
209 byte [] commentdata = new byte [length];
210 if (stream.Read (commentdata, 0, length) != length)
211 throw new System.Exception ("Incomplete Marker");
212 Marker m1 = new Marker (marker, commentdata, position);
213 marker_list.Add (m1);
214 app_marker_hash ["COM"] = m1;
215 break;
216 case JpegMarker.App0:
217 case JpegMarker.App1:
218 case JpegMarker.App2:
219 case JpegMarker.App3:
220 case JpegMarker.App4:
221 case JpegMarker.App5:
222 case JpegMarker.App6:
223 case JpegMarker.App7:
224 case JpegMarker.App8:
225 case JpegMarker.App9:
226 case JpegMarker.App10:
227 case JpegMarker.App11:
228 case JpegMarker.App12:
229 case JpegMarker.App13:
230 case JpegMarker.App14:
231 case JpegMarker.App15:
232 byte [] data = new byte [length];
233 if (stream.Read (data, 0, length) != length)
234 throw new System.Exception ("Incomplete Marker");
236 Marker m = new Marker (marker, data, position);
237 marker_list.Add (m);
238 this.AddNamed (m);
239 break;
240 case JpegMarker.Rst0:
241 case JpegMarker.Rst1:
242 case JpegMarker.Rst2:
243 case JpegMarker.Rst3:
244 case JpegMarker.Rst4:
245 case JpegMarker.Rst5:
246 case JpegMarker.Rst6:
247 case JpegMarker.Rst7:
248 case JpegMarker.Tem:
249 // These markers have no data it is in length_data
251 marker_list.Add (new Marker (marker, length_data, position));
252 break;
253 default:
254 byte [] d = new byte [length];
255 if (stream.Read (d, 0, length) != length)
256 throw new System.Exception ("Incomplete Marker");
258 marker_list.Add (new Marker (marker, d, position));
259 break;
262 if (marker == JpegMarker.Sos)
263 at_image = true;
267 #if false
268 public static int Main (string [] args)
270 JpegHeader data = new JpegHeader (args [0]);
271 byte [] value = data.GetRawXmp ();
273 if (value != null) {
274 string xml = System.Text.Encoding.UTF8.GetString (value, 29, value.Length - 29);
275 System.Console.WriteLine (xml);
278 value = data.GetRaw ("ICC_PROFILE");
279 if (value != null) {
280 System.IO.FileStream stream = new System.IO.FileStream ("profile.icc", System.IO.FileMode.Create);
281 stream.Write (value, 12, value.Length - 12);
282 stream.Close ();
285 value = data.GetRawExif ();
286 if (value != null) {
287 System.IO.MemoryStream stream = new System.IO.MemoryStream (value, 6, value.Length - 6);
288 Tiff.Header tiff = new Tiff.Header (stream);
289 tiff.Dump ();
292 return 0;
294 #endif