Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
EXIF.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
6
8{
15 public static class EXIF
16 {
17 private static readonly Dictionary<int, ExifTagName> names = GetNames();
18
19 private static Dictionary<int, ExifTagName> GetNames()
20 {
21 Dictionary<int, ExifTagName> Names = new Dictionary<int, ExifTagName>();
22
23 foreach (ExifTagName Value in Enum.GetValues(typeof(ExifTagName)))
24 Names[(int)Value] = Value;
25
26 return Names;
27 }
28
35 public static bool TryParse(byte[] ExifData, out ExifTag[] Tags)
36 {
37 ExifReader Reader = new ExifReader(ExifData);
38 List<ExifTag> List = new List<ExifTag>();
39
40 Tags = null;
41
42 // EXIF identifier
43 if (Reader.NextASCIIString() != "Exif")
44 return false;
45
46 // Padding
47 if (Reader.NextByte() < 0)
48 return false;
49
50 // Byte order
51 int RefPos = Reader.Position;
52 int i = Reader.NextSHORT();
53
54 switch (i)
55 {
56 case 0x4949:
57 Reader.BigEndian = false;
58 break;
59
60 case 0x4d4d:
61 Reader.BigEndian = true;
62 break;
63
64 default:
65 return false;
66 }
67
68 if (Reader.NextSHORT() != 0x2a)
69 return false;
70
71 // IFD 0 offset
72 uint? Offset = Reader.NextLONG();
73 if (!Offset.HasValue)
74 return false;
75
76 int Pos = RefPos + (int)Offset.Value;
77 if (Pos < Reader.Position || Pos >= Reader.Length)
78 return false;
79
80 Reader.Position = Pos;
81
82 do
83 {
84 int NrRecords = Reader.NextSHORT();
85 if (NrRecords < 0)
86 return false;
87
88 while (NrRecords > 0)
89 {
90 int TagID = Reader.NextSHORT();
91 if (TagID < 0)
92 return false;
93
94 if (!names.TryGetValue(TagID, out ExifTagName Name))
95 Name = ExifTagName.Unknown;
96
97 int Type = Reader.NextSHORT();
98 if (Type < 0)
99 return false;
100
101 uint? Count = Reader.NextLONG();
102 if (!Count.HasValue)
103 return false;
104
105 int ElementSize;
106 int NrElements = (int)Count.Value;
107
108 switch ((ExifTagType)Type)
109 {
110 case ExifTagType.ASCII:
111 ElementSize = 1;
112 NrElements = 1;
113 break;
114
115 case ExifTagType.BYTE:
116 case ExifTagType.UNDEFINED:
117 default:
118 ElementSize = 1;
119 break;
120
121 case ExifTagType.SHORT:
122 ElementSize = 2;
123 break;
124
125 case ExifTagType.LONG:
126 case ExifTagType.SLONG:
127 ElementSize = 4;
128 break;
129
130 case ExifTagType.RATIONAL:
131 case ExifTagType.SRATIONAL:
132 ElementSize = 8;
133 break;
134 }
135
136 int RecSize = (int)(Count.Value * ElementSize);
137 int PosBak;
138 int j;
139
140 if (RecSize <= 4)
141 PosBak = Reader.Position + 4;
142 else
143 {
144 uint? ValueOffset = Reader.NextLONG();
145 if (!ValueOffset.HasValue || RefPos + ValueOffset.Value > Reader.Length)
146 return false;
147
148 PosBak = Reader.Position;
149 Reader.Position = RefPos + (int)ValueOffset.Value;
150 }
151
152 switch ((ExifTagType)Type)
153 {
154 case ExifTagType.BYTE:
155 if (NrElements == 1)
156 {
157 i = Reader.NextByte();
158 if (i < 0)
159 return false;
160
161 List.Add(new ExifTypedTag<byte>(TagID, Name, (byte)i));
162 }
163 else
164 {
165 byte[] Items = new byte[NrElements];
166
167 for (j = 0; j < NrElements; j++)
168 {
169 i = Reader.NextByte();
170 if (i < 0)
171 return false;
172
173 Items[j] = (byte)i;
174 }
175
176 List.Add(new ExifTypedTag<byte[]>(TagID, Name, Items));
177 }
178 break;
179
180 case ExifTagType.ASCII:
181 string AsciiValue = Reader.NextASCIIString();
182 List.Add(new ExifAsciiTag(TagID, Name, AsciiValue));
183 break;
184
185 case ExifTagType.SHORT:
186 if (NrElements == 1)
187 {
188 i = Reader.NextSHORT();
189 if (i < 0)
190 return false;
191
192 List.Add(new ExifTypedTag<ushort>(TagID, Name, (ushort)i));
193 }
194 else
195 {
196 ushort[] Items = new ushort[NrElements];
197
198 for (j = 0; j < NrElements; j++)
199 {
200 i = Reader.NextSHORT();
201 if (i < 0)
202 return false;
203
204 Items[j] = (ushort)i;
205 }
206
207 List.Add(new ExifTypedTag<ushort[]>(TagID, Name, Items));
208 }
209 break;
210
211 case ExifTagType.LONG:
212 uint? u;
213
214 if (NrElements == 1)
215 {
216 u = Reader.NextLONG();
217 if (!u.HasValue)
218 return false;
219
220 List.Add(new ExifTypedTag<uint>(TagID, Name, u.Value));
221 }
222 else
223 {
224 uint[] Items = new uint[NrElements];
225
226 for (j = 0; j < NrElements; j++)
227 {
228 u = Reader.NextLONG();
229 if (!u.HasValue)
230 return false;
231
232 Items[j] = u.Value;
233 }
234
235 List.Add(new ExifTypedTag<uint[]>(TagID, Name, Items));
236 }
237 break;
238
239 case ExifTagType.RATIONAL:
240 if (NrElements == 1)
241 {
242 u = Reader.NextLONG();
243 if (!u.HasValue)
244 return false;
245
246 uint NumeratorValue = u.Value;
247
248 u = Reader.NextLONG();
249 if (!u.HasValue)
250 return false;
251
252 uint DenominatorValue = u.Value;
253 List.Add(new ExifTypedTag<Rational>(TagID, Name, new Rational(NumeratorValue, DenominatorValue)));
254 }
255 else
256 {
257 Rational[] Items = new Rational[NrElements];
258
259 for (j = 0; j < NrElements; j++)
260 {
261 u = Reader.NextLONG();
262 if (!u.HasValue)
263 return false;
264
265 uint NumeratorValue = u.Value;
266
267 u = Reader.NextLONG();
268 if (!u.HasValue)
269 return false;
270
271 uint DenominatorValue = u.Value;
272
273 Items[j] = new Rational(NumeratorValue, DenominatorValue);
274 }
275
276 List.Add(new ExifTypedTag<Rational[]>(TagID, Name, Items));
277 }
278 break;
279
280 case ExifTagType.UNDEFINED:
281 if (NrElements == 1)
282 {
283 i = Reader.NextByte();
284 if (i < 0)
285 return false;
286
287 List.Add(new ExifTypedTag<byte>(TagID, Name, (byte)i));
288 }
289 else
290 {
291 byte[] Items = new byte[NrElements];
292
293 for (j = 0; j < NrElements; j++)
294 {
295 i = Reader.NextByte();
296 if (i < 0)
297 return false;
298
299 Items[j] = (byte)i;
300 }
301
302 List.Add(new ExifTypedTag<byte[]>(TagID, Name, Items));
303 }
304 break;
305
306 case ExifTagType.SLONG:
307 if (NrElements == 1)
308 {
309 u = Reader.NextLONG();
310 if (!u.HasValue)
311 return false;
312
313 List.Add(new ExifTypedTag<int>(TagID, Name, (int)u.Value));
314 }
315 else
316 {
317 int[] Items = new int[NrElements];
318
319 for (j = 0; j < NrElements; j++)
320 {
321 u = Reader.NextLONG();
322 if (!u.HasValue)
323 return false;
324
325 Items[j] = (int)u.Value;
326 }
327
328 List.Add(new ExifTypedTag<int[]>(TagID, Name, Items));
329 }
330 break;
331
332 case ExifTagType.SRATIONAL:
333 if (NrElements == 1)
334 {
335 u = Reader.NextLONG();
336 if (!u.HasValue)
337 return false;
338
339 int NumeratorValue = (int)u.Value;
340
341 u = Reader.NextLONG();
342 if (!u.HasValue)
343 return false;
344
345 int DenominatorValue = (int)u.Value;
346 List.Add(new ExifTypedTag<SignedRational>(TagID, Name, new SignedRational(NumeratorValue, DenominatorValue)));
347 }
348 else
349 {
350 SignedRational[] Items = new SignedRational[NrElements];
351
352 for (j = 0; j < NrElements; j++)
353 {
354 u = Reader.NextLONG();
355 if (!u.HasValue)
356 return false;
357
358 int NumeratorValue = (int)u.Value;
359
360 u = Reader.NextLONG();
361 if (!u.HasValue)
362 return false;
363
364 int DenominatorValue = (int)u.Value;
365
366 Items[j] = new SignedRational(NumeratorValue, DenominatorValue);
367 }
368
369 List.Add(new ExifTypedTag<SignedRational[]>(TagID, Name, Items));
370 }
371 break;
372 }
373
374 Reader.Position = PosBak;
375 NrRecords--;
376 }
377
378 // Next IFD offset
379 Offset = Reader.NextLONG();
380 if (!Offset.HasValue)
381 return false;
382
383 if (Offset.Value == 0)
384 break;
385
386 Pos = RefPos + (int)Offset.Value;
387 if (Pos < Reader.Position || Pos >= Reader.Length)
388 return false;
389
390 Reader.Position = Pos;
391 }
392 while (true);
393
394 Tags = List.ToArray();
395 return true;
396 }
397
404 public static bool TryExtractFromJPeg(string FileName, out ExifTag[] Tags)
405 {
406 using (FileStream fs = File.OpenRead(FileName))
407 {
408 return TryExtractFromJPeg(fs, out Tags);
409 }
410 }
411
418 public static bool TryExtractFromJPeg(byte[] Image, out ExifTag[] Tags)
419 {
420 using (MemoryStream ms = new MemoryStream(Image))
421 {
422 return TryExtractFromJPeg(ms, out Tags);
423 }
424 }
425
432 public static bool TryExtractFromJPeg(Stream Image, out ExifTag[] Tags)
433 {
434 Tags = null;
435
436 if (Image.ReadByte() != 0xff)
437 return false;
438
439 if (Image.ReadByte() != 0xd8)
440 return false;
441
442 byte[] Buf = null;
443
444 do
445 {
446 if (!TryReadWord(Image, out ushort TagID))
447 return false;
448
449 if (!TryReadWord(Image, out ushort Len) || Len < 2)
450 return false;
451
452 Len -= 2;
453
454 switch (TagID)
455 {
456 case 0xffe1: //APP1
457 Buf = new byte[Len];
458
459 if (Image.TryReadAll(Buf, 0, Len) != Len)
460 return false;
461
462 return TryParse(Buf, out Tags);
463
464 default:
465 if (Image.CanSeek)
466 Image.Seek(Len, SeekOrigin.Current);
467 else
468 {
469 if (Buf is null || Buf.Length < Len)
470 Buf = new byte[Len];
471
472 if (Image.TryReadAll(Buf, 0, Len) != Len)
473 return false;
474 }
475 break;
476 }
477 }
478 while (true);
479 }
480
481 private static bool TryReadWord(Stream Input, out ushort w)
482 {
483 int i = Input.ReadByte();
484 if (i < 0)
485 {
486 w = 0;
487 return false;
488 }
489
490 w = (byte)i;
491
492 i = Input.ReadByte();
493 if (i < 0)
494 return false;
495
496 w <<= 8;
497 w |= (byte)i;
498
499 return true;
500 }
501
502 }
503}
Extracts EXIF meta-data from images.
Definition: EXIF.cs:16
static bool TryExtractFromJPeg(Stream Image, out ExifTag[] Tags)
Tries to extract EXIF meta-data from a JPEG stream.
Definition: EXIF.cs:432
static bool TryParse(byte[] ExifData, out ExifTag[] Tags)
Tries to parse EXIF data.
Definition: EXIF.cs:35
static bool TryExtractFromJPeg(byte[] Image, out ExifTag[] Tags)
Tries to extract EXIF meta-data from a JPEG image.
Definition: EXIF.cs:418
static bool TryExtractFromJPeg(string FileName, out ExifTag[] Tags)
Tries to extract EXIF meta-data from a JPEG image.
Definition: EXIF.cs:404
Class for ASCII-valued EXIF meta-data tags.
Definition: ExifAsciiTag.cs:9
uint? NextLONG()
Gets next LONG (unsigned int). If no more bytes are available, null is returned.
Definition: ExifReader.cs:108
string NextASCIIString()
Gets the next ASCII string.
Definition: ExifReader.cs:138
int NextByte()
Gets next byte. If no more bytes are available, -1 is returned.
Definition: ExifReader.cs:66
int Length
Length of data block
Definition: ExifReader.cs:44
int NextSHORT()
Gets next SHORT (unsigned short). If no more bytes are available, -1 is returned.
Definition: ExifReader.cs:78
Abstract base class for EXIF meta-data tags.
Definition: ExifTag.cs:10
Base class for typed EXIF meta-data tags.
Definition: ExifTypedTag.cs:9
Represents an EXIF RATIONAL value.
Definition: Rational.cs:11
Represents an EXIF SRATIONAL value.
ExifTagName
Defined EXIF Tag names
Definition: ExifTagName.cs:14
ExifTagType
Data types of meta-data tags
Definition: ExifTagType.cs:7