-
Notifications
You must be signed in to change notification settings - Fork 1
/
ExifHelper.cs
607 lines (585 loc) · 22 KB
/
ExifHelper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
/// Many pieces code of this file are just copy from the article
/// "Reading EXIF Tags From JPEG Files" posted by Steve McMahon.
/// http://vbaccelerator.com/home/NET/Code/Libraries/Graphics/Reading_EXIF_Tags_from_JPG_Files/article.asp
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace PhotoUtil
{
public enum EXIFIDCodes
{
/// <summary>
/// For other codes
/// </summary>
UnknownCode = 0x0,
/// <summary>
/// Describes image. Two-byte character code such as Chinese/Korean/Japanese cannot be used.
/// ascii string
/// </summary>
ImageDescription = 0x010e,
/// <summary>
/// Manfacturer of digicam. In the Exif standard, this tag is optional, but it is mandatory for DCF.
/// ascii string
/// </summary>
Manufacturer = 0x010f ,
/// <summary>
/// Shows model number of digicam. In the Exif standard, this tag is optional, but it is mandatory for DCF.
/// ascii string
/// </summary>
Model = 0x0110,
/// <summary>
/// The orientation of the camera relative to the scene, when the image was captured. The relation of the '0th row' and '0th column' to visual position is shown as right.
/// 1 top left side
/// 2 top right side
/// 3 bottom right side
/// 4 bottom left side
/// 5 left side top
/// 6 right side top
/// 7 right side bottom
/// 8 left side bottom
/// unsigned short 1
/// </summary>
Orientation = 0x0112,
/// <summary>
/// Display/Print resolution of image. Default value is 1/72inch, but it has no mean because personal computer doesn't use this value to display/print out.
/// unsigned rational 1
/// </summary>
XResolution = 0x011a,
/// <summary>
/// Display/Print resolution of image. Default value is 1/72inch, but it has no mean because personal computer doesn't use this value to display/print out.
/// unsigned rational 1
/// </summary>
YResolution = 0x011b,
/// <summary>
/// Unit of XResolution(0x011a)/YResolution(0x011b). '1' means no-unit, '2' means inch, '3' means centimeter. Default value is '2'(inch).
/// unsigned short 1
/// </summary>
ResolutionUnit = 0x0128,
/// <summary>
/// Shows firmware(internal software of digicam) version number.
/// ascii string
/// </summary>
Software = 0x0131,
/// <summary>
/// Date/Time of image was last modified. Data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20bytes. If clock has not set or digicam doesn't have clock, the field may be filled with spaces. In usual, it has the same value of DateTimeOriginal(0x9003)
/// ascii string 20
/// </summary>
DateTime = 0x0132 ,
/// <summary>
/// Defines chromaticity of white point of the image. If the image uses CIE Standard Illumination D65(known as international standard of 'daylight'), the values are '3127/10000,3290/10000'.
/// unsigned rational 2
/// </summary>
WhitePoint = 0x013e ,
/// <summary>
/// Defines chromaticity of the primaries of the image. If the image uses CCIR Recommendation 709 primaries, values are '640/1000,330/1000,300/1000,600/1000,150/1000,0/1000'.
/// unsigned rational 6
/// </summary>
PrimaryChromaticities = 0x013f,
/// <summary>
/// When image format is YCbCr, this value shows a constant to translate it to RGB format. In usual, values are '0.299/0.587/0.114'.
/// unsigned rational 3
/// </summary>
YCbCrCoefficients =0x0211,
/// <summary>
/// When image format is YCbCr and uses 'Subsampling'(cropping of chroma data, all the digicam do that), defines the chroma sample point of subsampling pixel array. '1' means the center of pixel array, '2' means the datum point.
/// unsigned short 1
/// </summary>
YCbCrPositioning = 0x0213 ,
/// <summary>
/// Shows reference value of black point/white point. In case of YCbCr format, first 2 show black/white of Y, next 2 are Cb, last 2 are Cr. In case of RGB format, first 2 show black/white of R, next 2 are G, last 2 are B.
/// unsigned rational 6
/// </summary>
ReferenceBlackWhite =0x0214,
/// <summary>
/// Shows copyright information
///ascii string
/// </summary>
Copyright = 0x8298,
/// <summary>
/// unsigned long 1 Offset to Exif Sub IFD
/// </summary>
ExifOffset =0x8769,
/// <summary>
/// Exposure time (reciprocal of shutter speed). Unit is second.
/// unsigned rational 1
/// </summary>
ExposureTime =0x829a,
/// <summary>
/// The actual F-number(F-stop) of lens when the image was taken.
/// unsigned rational 1
/// </summary>
FNumber = 0x829d,
/// <summary>
/// Exposure program that the camera used when image was taken. '1' means manual control, '2' program normal, '3' aperture priority, '4' shutter priority, '5' program creative (slow program), '6' program action(high-speed program), '7' portrait mode, '8' landscape mode.
/// unsigned short 1
/// </summary>
ExposureProgram =0x8822,
/// <summary>
/// CCD sensitivity equivalent to Ag-Hr film speedrate.
/// unsigned short 2
/// </summary>
ISOSpeedRatings =0x8827,
/// <summary>
/// Exif version number. Stored as 4bytes of ASCII character. If the picture is based on Exif V2.1, value is "0210". Since the type is 'undefined', there is no NULL(0x00) for termination.
/// undefined 4
/// </summary>
ExifVersion = 0x9000,
/// <summary>
/// Date/Time of original image taken. This value should not be modified by user program. Data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20bytes. If clock has not set or digicam doesn't have clock, the field may be filled with spaces. In the Exif standard, this tag is optional, but it is mandatory for DCF.
/// ascii string 20
/// </summary>
DateTimeOriginal = 0x9003,
/// <summary>
/// Date/Time of image digitized. Usually, it contains the same value of DateTimeOriginal(0x9003). Data format is "YYYY:MM:DD HH:MM:SS"+0x00, total 20bytes. If clock has not set or digicam doesn't have clock, the field may be filled with spaces. In the Exif standard, this tag is optional, but it is mandatory for DCF.
/// ascii string 20
/// </summary>
DateTimeDigitized = 0x9004,
/// <summary>
/// Shows the order of pixel data. Most of case '0x04,0x05,0x06,0x00' is used for RGB-format and '0x01,0x02,0x03,0x00' for YCbCr-format. 0x00:does not exist, 0x01:Y, 0x02:Cb, 0x03:Cr, 0x04:Red, 0x05:Green, 0x06:Bllue.
/// undefined
/// </summary>
ComponentsConfiguration =0x9101,
/// <summary>
/// The average compression ratio of JPEG (rough estimate).
/// unsigned rational 1
/// </summary>
CompressedBitsPerPixel =0x9102,
/// <summary>
/// Shutter speed by APEX value. To convert this value to ordinary 'Shutter Speed'; calculate this value's power of 2, then reciprocal. For example, if the ShutterSpeedValue is '4', shutter speed is 1/(24)=1/16 second.
/// signed rational 1
/// </summary>
ShutterSpeedValue = 0x9201,
/// <summary>
/// The actual aperture value of lens when the image was taken. Unit is APEX. To convert this value to ordinary F-number(F-stop), calculate this value's power of root 2 (=1.4142). For example, if the ApertureValue is '5', F-number is Pow(1.4142,5) = F5.6.
/// unsigned rational 1
/// </summary>
ApertureValue =0x9202,
/// <summary>
/// Brightness of taken subject, unit is APEX. To calculate Exposure(Ev) from BrigtnessValue(Bv), you must add SensitivityValue(Sv).
/// Ev=Bv+Sv Sv=log2(ISOSpeedRating/3.125)
/// ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32.
/// signed rational 1
/// </summary>
BrightnessValue =0x9203,
/// <summary>
/// Exposure bias(compensation) value of taking picture. Unit is APEX(EV).
/// signed rational 1
/// </summary>
ExposureBiasValue =0x9204 ,
/// <summary>
/// Maximum aperture value of lens. You can convert to F-number by calculating power of root 2 (same process of ApertureValue:0x9202).
///unsigned rational 1
/// </summary>
MaxApertureValue = 0x9205,
/// <summary>
/// Distance to focus point, unit is meter.
/// signed rational 1
/// </summary>
SubjectDistance = 0x9206,
/// <summary>
/// Exposure metering method. '0' means unknown, '1' average, '2' center weighted average, '3' spot, '4' multi-spot, '5' multi-segment, '6' partial, '255' other.
/// unsigned short 1
/// </summary>
MeteringMode = 0x9207,
/// <summary>
/// Light source, actually this means white balance setting. '0' means unknown, '1' daylight, '2' fluorescent, '3' tungsten, '10' flash, '17' standard light A, '18' standard light B, '19' standard light C, '20' D55, '21' D65, '22' D75, '255' other.
/// unsigned short 1
/// </summary>
LightSource = 0x9208,
/// <summary>
/// '0' means flash did not fire, '1' flash fired, '5' flash fired but strobe return light not detected, '7' flash fired and strobe return light detected.
/// unsigned short 1
/// </summary>
Flash = 0x9209,
/// <summary>
/// Focal length of lens used to take image. Unit is millimeter.
/// unsigned rational 1
/// </summary>
FocalLength = 0x920a,
/// <summary>
/// Maker dependent internal data. Some of maker such as Olympus/Nikon/Sanyo etc. uses IFD format for this area.
/// undefined
/// </summary>
MakerNote =0x927c,
/// <summary>
/// Stores user comment. This tag allows to use two-byte character code or unicode. First 8 bytes describe the character code. 'JIS' is a Japanese character code (known as Kanji).
/// '0x41,0x53,0x43,0x49,0x49,0x00,0x00,0x00':ASCII
///'0x4a,0x49,0x53,0x00,0x00,0x00,0x00,0x00':JIS
///'0x55,0x4e,0x49,0x43,0x4f,0x44,0x45,0x00':Unicode
///'0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00':Undefined
/// undefined
/// </summary>
UserComment =0x9286,
/// <summary>
///Some of digicam can take 2~30 pictures per second, but DateTime/DateTimeOriginal/DateTimeDigitized tag can't record the sub-second time. SubsecTime tag is used to record it.
/// For example, DateTimeOriginal = "1996:09:01 09:15:30", SubSecTimeOriginal = "130", Combined original time is "1996:09:01 09:15:30.130"
/// ascii string
/// </summary>
SubsecTime =0x9290,
/// <summary>
/// See SubsecTime
/// ascii string
/// </summary>
SubsecTimeOriginal =0x9291,
/// <summary>
/// See SubsecTime
/// ascii string
/// </summary>
SubsecTimeDigitized = 0x9292,
/// <summary>
/// Stores FlashPix version. If the image data is based on FlashPix formar Ver.1.0, value is "0100". Since the type is 'undefined', there is no NULL(0x00) for termination.
/// undefined 4
/// </summary>
FlashPixVersion = 0xa000,
/// <summary>
/// Defines Color Space. DCF image must use sRGB color space so value is always '1'. If the picture uses the other color space, value is '65535':Uncalibrated.
/// unsigned short 1
/// </summary>
ColorSpace = 0xa001,
/// <summary>
/// Size of main image.
/// unsigned short/long 1
/// </summary>
ExifImageWidth = 0xa002,
/// <summary>
/// Size of main image
/// unsigned short/long 1
/// </summary>
ExifImageHeight = 0xa003,
/// <summary>
/// If this digicam can record audio data with image, shows name of audio data.
/// ascii string
/// </summary>
RelatedSoundFile = 0xa004,
/// <summary>
/// Extension of "ExifR98", detail is unknown. This value is offset to IFD format data. Currently there are 2 directory entries, first one is Tag0x0001, value is "R98", next is Tag0x0002, value is "0100".
/// unsigned long 1
/// </summary>
ExifInteroperabilityOffset = 0xa005,
/// <summary>
/// Pixel density at CCD's position. If you have MegaPixel digicam and take a picture by lower resolution(e.g.VGA mode), this value is re-sampled by picture resolution. In such case, FocalPlaneResolution is not same as CCD's actual resolution.
/// unsigned rational 1
/// </summary>
FocalPlaneXResolution =0xa20e,
/// <summary>
/// See FocalPlaneXResolution
/// unsigned rational 1
/// </summary>
FocalPlaneYResolution = 0xa20f,
/// <summary>
/// Unit of FocalPlaneXResoluton/FocalPlaneYResolution. '1' means no-unit, '2' inch, '3' centimeter.
/// Note:Some of Fujifilm's digicam(e.g.FX2700,FX2900,Finepix4700Z/40i etc) uses value '3' so it must be 'centimeter', but it seems that they use a '8.3mm?'(1/3in.?) to their ResolutionUnit. Fuji's BUG? Finepix4900Z has been changed to use value '2' but it doesn't match to actual value also.
/// unsigned short 1
/// </summary>
FocalPlaneResolutionUnit =0xa210,
/// <summary>
/// Same as ISOSpeedRatings(0x8827) but data type is unsigned rational. Only Kodak's digicam uses this tag instead of ISOSpeedRating, I don't know why(historical reason?).
/// unsigned rational 1
/// </summary>
ExposureIndex =0xa215,
/// <summary>
/// Shows type of image sensor unit. '2' means 1 chip color area sensor, most of all digicam use this type.
/// unsigned short 1
/// </summary>
SensingMethod =0xa217 ,
/// <summary>
/// Indicates the image source. Value '0x03' means the image source is digital still camera.
/// undefined 1
/// </summary>
FileSource =0xa300,
/// <summary>
/// Indicates the type of scene. Value '0x01' means that the image was directly photographed.
/// undefined 1
/// </summary>
SceneType =0xa301,
/// <summary>
/// Indicates the Color filter array(CFA) geometric pattern.
/// Length Type Meaning
/// 2 short Horizontal repeat pixel unit = n
/// 2 short Vertical repeat pixel unit = m
/// 1 byte CFA value[0,0]
/// 1 byte CFA value[n-1,0]
/// 1 byte CFA value[0,1]
/// 1 byte CFA value[n-1,m-1]
///
///The relation of filter color to CFA value is shown below.
/// Red = 0 Green = 1 Blue = 2 Cyan = 3 Magenta = 4 Yellow = 5 White = 6
///
/// undefined
/// </summary>
CFAPattern =0xa302,
/// <summary>
/// If this IFD is main image's IFD and the file content is equivalent to ExifR98 v1.0, the value is "R98". If thumbnail image's, value is "THM".
/// Ascii string 4
/// </summary>
InteroperabilityIndex = 0x0001,
/// <summary>
/// Records the interoperability version. "0100" means version 1.00.
/// Undefined 4
/// </summary>
InteroperabilityVersion =0x0002 ,
/// <summary>
/// Records the file format of image file. Value is ascii string (e.g. "Exif JPEG Ver. 2.1").
/// Ascii string any
/// </summary>
RelatedImageFileFormat = 0x1000,
/// <summary>
/// Records the image size.
/// Short or Long 1
/// </summary>
RelatedImageWidth =0x1001,
/// <summary>
/// Records the image size
/// Short or Long 1
/// </summary>
RelatedImageLength = 0x1001,
/// <summary>
/// Shows size of thumbnail image.
/// unsigned short/long 1
/// </summary>
ImageWidth = 0x0100,
/// <summary>
/// Shows size of thumbnail image.
/// unsigned short/long 1
/// </summary>
ImageLength = 0x0101,
/// <summary>
/// When image format is no compression, this value shows the number of bits per component for each pixel. Usually this value is '8,8,8'
/// unsigned short 3
/// </summary>
BitsPerSample =0x0102,
/// <summary>
/// Shows compression method. '1' means no compression, '6' means JPEG compression.
/// unsigned short 1
/// </summary>
Compression =0x0103,
/// <summary>
/// Shows the color space of the image data components. '1' means monochrome, '2' means RGB, '6' means YCbCr.
/// unsigned short 1
/// </summary>
PhotometricInterpretation = 0x0106,
/// <summary>
/// When image format is no compression, this value shows offset to image data. In some case image data is striped and this value is plural.
/// unsigned short/long
/// </summary>
StripOffsets = 0x0111,
/// <summary>
/// When image format is no compression, this value shows the number of components stored for each pixel. At color image, this value is '3'.
/// unsigned short 1
/// </summary>
SamplesPerPixel = 0x0115,
/// <summary>
/// When image format is no compression and image has stored as strip, this value shows how many rows stored to each strip. If image has not striped, this value is the same as ImageLength(0x0101).
/// unsigned short/long 1
/// </summary>
RowsPerStrip = 0x0116,
/// <summary>
/// When image format is no compression and stored as strip, this value shows how many bytes used for each strip and this value is plural. If image has not stripped, this value is single and means whole data size of image.
/// unsigned short/long
/// </summary>
StripByteConunts = 0x0117 ,
/// <summary>
/// When image format is no compression YCbCr, this value shows byte aligns of YCbCr data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for each subsampling pixel. If value is '2', Y/Cb/Cr value is separated and stored to Y plane/Cb plane/Cr plane format.
/// unsigned short 1
/// </summary>
PlanarConfiguration = 0x011c,
/// <summary>
/// When image format is JPEG, this value show offset to JPEG data stored.
/// unsigned long 1
/// </summary>
JpegIFOffset = 0x0201,
/// <summary>
/// When image format is JPEG, this value shows data size of JPEG image.
/// unsigned long 1
/// </summary>
JpegIFByteCount =0x0202,
/// <summary>
/// When image format is YCbCr and uses subsampling(cropping of chroma data, all the digicam do that), this value shows how many chroma data subsampled. First value shows horizontal, next value shows vertical subsample rate.
/// unsigned short 2
/// </summary>
YCbCrSubSampling =0x0212 ,
}
public enum EXIFPropertyTypes
{
/// <summary>
/// Data contains unsigned bytes
/// </summary>
UnsignedByte = 1,
/// <summary>
/// Data contains a string
/// </summary>
String = 2,
/// <summary>
/// Data contains unsigned 2-byte values
/// </summary>
UnsignedChar = 3,
/// <summary>
/// Data contains unsigned 4-byte values
/// </summary>
UnsignedInt = 4,
/// <summary>
/// Data is fractional: each item in the data is 8 bytes long.
/// The first 4 bytes of each item in the data contain the
/// numerator (unsigned int), the second 4 bytes the denominator
/// (also unsigned int).
/// </summary>
UnsignedRational = 5,
/// <summary>
/// Data contains signed bytes
/// </summary>
SignedByte = 6,
/// <summary>
/// Data has arbitrary data type, tag specific
/// </summary>
Undefined = 7,
/// <summary>
/// Data contains signed 2-byte values
/// </summary>
SignedChar = 8,
/// <summary>
/// Data contains signed 4-byte values
/// </summary>
SignedInt = 9,
/// <summary>
/// Data is fractional: each item in the data is 8 bytes long.
/// The first 4 bytes of each item in the data contain the
/// numerator (signed int), the second 4 bytes the denominator
/// (also signed int).
/// </summary>
SignedRational = 10,
/// <summary>
/// Data contains 4-byte floating point values
/// </summary>
Float = 11,
/// <summary>
/// Data contains 8-byte floating point values
/// </summary>
Double = 12
}
/// <summary>
/// A structure containing an EXIFRational value
/// </summary>
public struct EXIFRational
{
/// <summary>
///
/// </summary>
public int Denominator;
public int Numerator;
/// <summary>
/// Creates an EXIFRational object from EXIF byte data
/// </summary>
/// <param name="data">Byte data to create from</param>
public EXIFRational(byte[] data) : this(data, 0)
{
}
/// <summary>
/// Creates an EXIFRational object from EXIF byte data,
/// starting at the byte specified by ofs
/// </summary>
/// <param name="data">EXIF byte data</param>
/// <param name="ofs">Initial Byte</param>
public EXIFRational(byte[] data, int ofs)
{
Numerator = ExifHelper.ReadInt32(data, ofs);
Denominator = ExifHelper.ReadInt32(data, ofs + 4);
}
/// <summary>
/// Returns the value of the fraction as a string
/// </summary>
/// <returns>The value of the fraction as a string</returns>
public override string ToString()
{
string ret;
if (this.Denominator == 0)
{
ret = "N/A";
}
else
{
ret = String.Format("{0:F2}", this.Numerator * 1.0/this.Denominator);
}
return ret;
}
}
public class ExifHelper
{
public static string GetPropertyString(PropertyItem propItem)
{
byte[] data = propItem.Value;
string text = "";
if (data.Length > 1)
{
IntPtr h = Marshal.AllocHGlobal(data.Length);
int i = 0;
foreach (byte b in data)
{
Marshal.WriteByte(h, i, b);
i++;
}
text = Marshal.PtrToStringAnsi(h);
Marshal.FreeHGlobal(h);
}
return text;
}
public static Int32 GetPropertyInt32(PropertyItem propItem)
{
return ReadInt32(propItem.Value, 0);
}
public static EXIFRational GetPropertyRational(PropertyItem propItem)
{
return new EXIFRational(propItem.Value);
}
public static DateTime GetPropertyDateTime(PropertyItem propItem)
{
string date = GetPropertyString(propItem);
try
{
if (date.Length >= 19)
{
int year = int.Parse(date.Substring(0, 4));
int month = int.Parse(date.Substring(5,2));
int day = int.Parse(date.Substring(8,2));
int hour = int.Parse(date.Substring(11,2));
int minute = int.Parse(date.Substring(14,2));
int second = int.Parse(date.Substring(17,2));
return new DateTime(year, month, day, hour, minute, second);
}
}
catch
{}
throw new Exception(string.Format("The property ({0}) is not in DateTime format!", propItem.Id));
}
public static Int32 ReadInt32(byte[] data, int ofs)
{
if (data.Length - ofs < 4)
throw new Exception(string.Format("The data (offset={0}) length is valid!", ofs));
IntPtr h = Marshal.AllocHGlobal(4);
for(int i = 0; i < 4; i++)
{
Marshal.WriteByte(h, i, data[ofs+i]);
}
Int32 ret = Marshal.ReadInt32(h);
Marshal.FreeHGlobal(h);
return ret;
}
public static string GetImageTakenTimeString(Image image, string format)
{
string text;
try
{
PropertyItem pi = image.GetPropertyItem((int)EXIFIDCodes.DateTimeOriginal);
text = (null == pi) ?
"Not available!"
:
ExifHelper.GetPropertyDateTime(pi).ToString(format);
}
catch(Exception ex)
{
text = ex.Message;
}
return text;
}
}
}