C# Exif code,metadata extraction in java读取照片文件的属性
FROM: http://sourceforge.net/projects/metadataspr/
http://www.drewnoakes.com/code/exif/
http://www.holmessoft.co.uk/homepage/Software/ExifUsage.htm
http://www.exif.org/samples.html
Write EXIF metadata to a jpeg file http://www.dreamincode.net/code/snippet3144.htm
代码
1
2 public ModifyJpgMetadata()
3
4 {
5
6 //
7
8 // get the path to some jpg file
9
10 //
11
12 string jpegPath = "C:\\users\\scott\\Pictures\\sample\\xxxjpg";
13
14 string jpegDirectory = PathGetDirectoryName(jpegPath);
15
16 string jpegFileName = PathGetFileNameWithoutExtension(jpegPath);
17
18 string jpegExtension = "jpg";
19
20
21
22 BitmapDecoder decoder = null;
23
24 BitmapFrame bitmapFrame = null;
25
26 BitmapMetadata metadata = null;
27
28 if (FileExists(jpegPath))
29
30 {
31
32 //
33
34 // load the jpg file with a JpegBitmapDecoder
35
36 //
37
38 using (Stream jpegStreamIn = FileOpen(jpegPath, FileModeOpen, FileAccessReadWrite, FileShareNone))
39
40 {
41
42 decoder = new JpegBitmapDecoder(jpegStreamIn, BitmapCreateOptionsPreservePixelFormat, BitmapCacheOptionOnLoad);
43
44 }
45
46
47
48 bitmapFrame = decoderFrames[];
49
50 metadata = (BitmapMetadata)bitmapFrameMetadata;
51
52
53
54 if (bitmapFrame != null)
55
56 {
57
58 //
59
60 // now get an InPlaceBitmapMetadataWriter, modify the metadata and try to save
61
62 //
63
64 InPlaceBitmapMetadataWriter writer = bitmapFrameCreateInPlaceBitmapMetadataWriter();
65
66 writerSetQuery("/app/ifd/exif:{uint=}", ":: ::");
67
68 if (!writerTrySave() == true)
69
70 {
71
72 //
73
74 // the size of the metadata has been increased and we can't save it
75
76 //
77
78 uint padding = ;
79
80
81
82 BitmapMetadata metaData = (BitmapMetadata)bitmapFrameMetadataClone();
83
84 if (metaData != null)
85
86 {
87
88 //
89
90 // Add padding
91
92 //
93
94 metaDataSetQuery("/app/ifd/PaddingSchema:Padding", padding);
95
96 //
97
98 // modify the metadata
99
100 metaDataSetQuery("/app/ifd/exif:{uint=}", ":: ::");
101
102 metaDataSetQuery("/app/ifd/exif:{uint=}", ":: ::");
103
104 metaDataSetQuery("/app/ifd/exif:{uint=}", ":: ::");
105
106 //
107
108 // get an encoder to create a new jpg file with the addit'l metadata
109
110 //
111
112 JpegBitmapEncoder encoder = new JpegBitmapEncoder();
113
114 encoderFramesAdd(BitmapFrameCreate(bitmapFrame, bitmapFrameThumbnail, metaData, bitmapFrameColorContexts));
115
116 string jpegNewFileName = PathCombine(jpegDirectory, "JpegTempjpg");
117
118 using (Stream jpegStreamOut = FileOpen(jpegNewFileName, FileModeCreateNew, FileAccessReadWrite))
119
120 {
121
122 encoderSave(jpegStreamOut);
123
124 }
125
126 //
127
128 // see if the metadata was really changed
129
130 //
131
132 using (Stream jpegStreamIn = FileOpen(jpegNewFileName, FileModeOpen, FileAccessReadWrite))
133
134 {
135
136 decoder = new JpegBitmapDecoder(jpegStreamIn, BitmapCreateOptionsPreservePixelFormat, BitmapCacheOptionOnLoad);
137
138 BitmapFrame frame = decoderFrames[];
139
140 BitmapMetadata bmd = (BitmapMetadata)frameMetadata;
141
142 string a = (string)bmdGetQuery("/app/ifd/exif:{uint=}");
143
144 string a = (string)bmdGetQuery("/app/ifd/exif:{uint=}");
145
146 string a = (string)bmdGetQuery("/app/ifd/exif:{uint=}");
147
148 }
149
150 }
151
152 }
153
154 }
155
156 }
157
158 }
159
160
2 public ModifyJpgMetadata()
3
4 {
5
6 //
7
8 // get the path to some jpg file
9
10 //
11
12 string jpegPath = "C:\\users\\scott\\Pictures\\sample\\xxxjpg";
13
14 string jpegDirectory = PathGetDirectoryName(jpegPath);
15
16 string jpegFileName = PathGetFileNameWithoutExtension(jpegPath);
17
18 string jpegExtension = "jpg";
19
20
21
22 BitmapDecoder decoder = null;
23
24 BitmapFrame bitmapFrame = null;
25
26 BitmapMetadata metadata = null;
27
28 if (FileExists(jpegPath))
29
30 {
31
32 //
33
34 // load the jpg file with a JpegBitmapDecoder
35
36 //
37
38 using (Stream jpegStreamIn = FileOpen(jpegPath, FileModeOpen, FileAccessReadWrite, FileShareNone))
39
40 {
41
42 decoder = new JpegBitmapDecoder(jpegStreamIn, BitmapCreateOptionsPreservePixelFormat, BitmapCacheOptionOnLoad);
43
44 }
45
46
47
48 bitmapFrame = decoderFrames[];
49
50 metadata = (BitmapMetadata)bitmapFrameMetadata;
51
52
53
54 if (bitmapFrame != null)
55
56 {
57
58 //
59
60 // now get an InPlaceBitmapMetadataWriter, modify the metadata and try to save
61
62 //
63
64 InPlaceBitmapMetadataWriter writer = bitmapFrameCreateInPlaceBitmapMetadataWriter();
65
66 writerSetQuery("/app/ifd/exif:{uint=}", ":: ::");
67
68 if (!writerTrySave() == true)
69
70 {
71
72 //
73
74 // the size of the metadata has been increased and we can't save it
75
76 //
77
78 uint padding = ;
79
80
81
82 BitmapMetadata metaData = (BitmapMetadata)bitmapFrameMetadataClone();
83
84 if (metaData != null)
85
86 {
87
88 //
89
90 // Add padding
91
92 //
93
94 metaDataSetQuery("/app/ifd/PaddingSchema:Padding", padding);
95
96 //
97
98 // modify the metadata
99
100 metaDataSetQuery("/app/ifd/exif:{uint=}", ":: ::");
101
102 metaDataSetQuery("/app/ifd/exif:{uint=}", ":: ::");
103
104 metaDataSetQuery("/app/ifd/exif:{uint=}", ":: ::");
105
106 //
107
108 // get an encoder to create a new jpg file with the addit'l metadata
109
110 //
111
112 JpegBitmapEncoder encoder = new JpegBitmapEncoder();
113
114 encoderFramesAdd(BitmapFrameCreate(bitmapFrame, bitmapFrameThumbnail, metaData, bitmapFrameColorContexts));
115
116 string jpegNewFileName = PathCombine(jpegDirectory, "JpegTempjpg");
117
118 using (Stream jpegStreamOut = FileOpen(jpegNewFileName, FileModeCreateNew, FileAccessReadWrite))
119
120 {
121
122 encoderSave(jpegStreamOut);
123
124 }
125
126 //
127
128 // see if the metadata was really changed
129
130 //
131
132 using (Stream jpegStreamIn = FileOpen(jpegNewFileName, FileModeOpen, FileAccessReadWrite))
133
134 {
135
136 decoder = new JpegBitmapDecoder(jpegStreamIn, BitmapCreateOptionsPreservePixelFormat, BitmapCacheOptionOnLoad);
137
138 BitmapFrame frame = decoderFrames[];
139
140 BitmapMetadata bmd = (BitmapMetadata)frameMetadata;
141
142 string a = (string)bmdGetQuery("/app/ifd/exif:{uint=}");
143
144 string a = (string)bmdGetQuery("/app/ifd/exif:{uint=}");
145
146 string a = (string)bmdGetQuery("/app/ifd/exif:{uint=}");
147
148 }
149
150 }
151
152 }
153
154 }
155
156 }
157
158 }
159
160
http://www.koders.com/csharp/fid6E5A26A44CC15C401B9D4B4C11EE862ECB6B1D26.aspx?s=Exif.cs#L2
http://www.koders.com/csharp/fid79911D36AE70DCCBB585B72801A5BD591CFCA41E.aspx?s=Exif.cs#L2
代码
1 //
2 // Exif.cs : LibExif wrapper for FSpot
3 //
4 // Author:
5 // Larry Ewing (lewing@novell.com)
6 // Ravi Pratap (ravi@ximian.com)
7 // Miguel de Icaza (miguel@ximian.com)
8 //
9 // (C) 2002, 2004, 2005 Novell, Inc.
10 //
11
12 using System;
13 using System.Collections;
14 using System.Runtime.InteropServices;
15
16 using Mono.Unix;
17
18 namespace Exif {
19 public enum Tag {
20 InteroperabilityIndex = 0x0001,
21 InteroperabilityVersion = 0x0002,
22 ImageWidth = 0x0100,
23 ImageHeight = 0x0101,
24 BitsPersample = 0x0102,
25 Compression = 0x0103,
26 PhotometricInterpretation = 0x0106,
27 FillOrder = 0x010a,
28 DocumentName = 0x010d,
29 ImageDescription = 0x010e,
30 Make = 0x010f,
31 Model = 0x0110,
32 StripOffsets = 0x0111,
33 Orientation = 0x0112,
34 SamplesPerPixel = 0x0115,
35 RowsPerStrip = 0x0116,
36 StripByteCounts = 0x0117,
37 XResolution = 0x011a,
38 YResolution = 0x011b,
39 PlanarConfiguration = 0x011c,
40 ResolutionUnit = 0x0128,
41 TransferFunction = 0x012d,
42 Software = 0x0131,
43 DateTime = 0x0132,
44 Artist = 0x013b,
45 WhitePoint = 0x013e,
46 PrimaryChromaticities = 0x013f,
47 TransferRange = 0x0156,
48 JPEGProc = 0x0200,
49 JPEGInterchangeFormat = 0x0201,
50 JPEGInterchangeFormatLength = 0x0202,
51 YCBCRCoefficients = 0x0211,
52 YCBCRSubSampling = 0x0212,
53 YCBCRPositioning = 0x0213,
54 ReferenceBlackWhite = 0x0214,
55 RelatedImageFileFormat = 0x1000,
56 RelatedImageWidth = 0x1001,
57 RelatedImageHeight = 0x1002,
58 CFARepeatPatternDim = 0x828d,
59 CFAPattern = 0x828e,
60 BatteryLevel = 0x828f,
61 Copyright = 0x8298,
62 ExposureTime = 0x829a,
63 FNumber = 0x829d,
64 IPTCNAA = 0x83bb,
65 ExifIfdPointer = 0x8769,
66 InterColorProfile = 0x8773,
67 ExposureProgram = 0x8822,
68 SpectralSensitivity = 0x8824,
69 GPSInfoIfdPointer = 0x8825,
70 ISOSpeedRatings = 0x8827,
71 OECF = 0x8828,
72 ExifVersion = 0x9000,
73 DateTimeOriginal = 0x9003,
74 DateTimeDigitized = 0x9004,
75 ComponentsConfiguration = 0x9101,
76 CompressedBitsPerPixel = 0x9102,
77 ShutterSpeedValue = 0x9201,
78 ApertureValue = 0x9202,
79 BrightnessValue = 0x9203,
80 ExposureBiasValue = 0x9204,
81 MaxApertureValue = 0x9205,
82 SubjectDistance = 0x9206,
83 MeteringMode = 0x9207,
84 LightSource = 0x9208,
85 Flash = 0x9209,
86 FocalLength = 0x920a,
87 SubjectArea = 0x9214,
88 MakerNote = 0x927c,
89 UserComment = 0x9286,
90 SubSecTime = 0x9290,
91 SubSecTimeOriginal = 0x9291,
92 SubSecTimeDigitized = 0x9292,
93 FlashPixVersion = 0xa000,
94 ColorSpace = 0xa001,
95 PixelXDimension = 0xa002,
96 PixelYDimension = 0xa003,
97 RelatedSoundFile = 0xa004,
98 InteroperabilityIfdPointer = 0xa005,
99 FlashEnergy = 0xa20b,
100 SpatialFrequencyResponse = 0xa20c,
101 FocalPlaneXResolution = 0xa20e,
102 FocalPlaneYResolution = 0xa20f,
103 FocalPlaneResolutionUnit = 0xa210,
104 SubjectLocation = 0xa214,
105 ExposureIndex = 0xa215,
106 SensingMethod = 0xa217,
107 FileSource = 0xa300,
108 SceneType = 0xa301,
109 NewCFAPattern = 0xa302,
110 CustomRendered = 0xa401,
111 ExposureMode = 0xa402,
112 WhiteBalance = 0xa403,
113 DigitalZoomRatio = 0xa404,
114 FocalLengthIn35mmFilm = 0xa405,
115 SceneCaptureType = 0xa406,
116 GainControl = 0xa407,
117 Contrast = 0xa408,
118 Saturation = 0xa409,
119 Sharpness = 0xa40a,
120 DeviceSettingDescription = 0xa40b,
121 SubjectDistanceRange = 0xa40c,
122 ImageUniqueId = 0xa420,
123
124 // The Following IDs are not described the EXIF spec
125
126 // The XMP spec declares that XMP data should live 0x2bc when
127 // embedded in tiff images.
128 XMP = 0x02bc,
129
130 // Print Image Matching data
131 PimIfdPointer = 0xc4a5
132 }
133
134 public enum ByteOrder {
135 Motorola,
136 Intel
137 }
138
139 public enum ExifFormat {
140 Byte = 1,
141 Ascii = 2,
142 Short = 3,
143 Long = 4,
144 Rational = 5,
145 Undefined = 7,
146 Slong = 9,
147 SRational = 10
148 }
149
150 public enum Ifd {
151 Zero = 0,
152 One,
153 Exif,
154 Gps,
155 InterOperability,
156 Count
157 }
158
159 internal class ExifUtil {
160
161 [DllImport ("libexif.dll")]
162 static extern IntPtr exif_tag_get_name (Tag tag);
163
164 [DllImport ("libexif.dll")]
165 static extern IntPtr exif_tag_get_title (Tag tag);
166
167 [DllImport ("libexif.dll")]
168 static extern IntPtr exif_tag_get_description (Tag tag);
169
170 [DllImport ("libexif.dll")]
171 static extern IntPtr exif_byte_order_get_name (ByteOrder order);
172
173 [DllImport ("libexif.dll")]
174 static extern IntPtr exif_format_get_name (ExifFormat format);
175
176 [DllImport ("libexif.dll")]
177 static extern char exif_format_get_size (ExifFormat format);
178
179 [DllImport ("libexif.dll")]
180 static extern IntPtr exif_ifd_get_name (Ifd ifd);
181
182 public static string GetTagName (Tag tag)
183 {
184
185 IntPtr raw_ret = exif_tag_get_name (tag);
186 return Marshal.PtrToStringAnsi (raw_ret);
187 }
188
189 public static string GetTagTitle (Tag tag)
190 {
191 IntPtr raw_ret = exif_tag_get_title (tag);
192 return Marshal.PtrToStringAnsi (raw_ret);
193 }
194
195 public static string GetTagDescription (Tag tag)
196 {
197 IntPtr raw_ret = exif_tag_get_description (tag);
198 return Marshal.PtrToStringAnsi (raw_ret);
199 }
200
201 public static string GetByteOrderName (ByteOrder order)
202 {
203 IntPtr raw_ret = exif_byte_order_get_name (order);
204 return Marshal.PtrToStringAnsi (raw_ret);
205 }
206
207 public static string GetFormatName (ExifFormat format)
208 {
209 IntPtr raw_ret = exif_format_get_name (format);
210 return Marshal.PtrToStringAnsi (raw_ret);
211 }
212
213 public static char GetFormatSize (ExifFormat format)
214 {
215 return exif_format_get_size (format);
216 }
217
218 public static string GetIfdName (Ifd ifd)
219 {
220 IntPtr raw_ret = exif_ifd_get_name (ifd);
221 return Marshal.PtrToStringAnsi (raw_ret);
222 }
223
224 public static string GetIfdNameExtended (Ifd ifd)
225 {
226 switch (ifd) {
227 case Ifd.Zero:
228 return Catalog.GetString ("Image Directory");
229 case Ifd.One:
230 return Catalog.GetString ("Thumbnail Directory");
231 case Ifd.Exif:
232 return Catalog.GetString ("Exif Directory");
233 case Ifd.Gps:
234 return Catalog.GetString ("GPS Directory");
235 case Ifd.InterOperability:
236 return Catalog.GetString ("InterOperability Directory");
237 default:
238 return Catalog.GetString ("Unknown Directory");
239 }
240 }
241
242 public static DateTime DateTimeFromString(string dt)
243 {
244 // Exif DateTime strings are formatted as
245 // "YYYY:MM:DD HH:MM:SS"
246
247 string delimiters = " :";
248 string[] dt_data = dt.Split ( delimiters.ToCharArray(), 6 );
249 DateTime result;
250 result = new DateTime (Int32.Parse(dt_data[0]), Int32.Parse(dt_data[1]), Int32.Parse(dt_data[2]),
251 Int32.Parse(dt_data[3]), Int32.Parse(dt_data[4]), Int32.Parse(dt_data[5]));
252
253 return result;
254 }
255
256 }
257
258 public abstract class ExifObject : IDisposable {
259 protected HandleRef handle;
260
261 public HandleRef Handle {
262 get {
263 return handle;
264 }
265 }
266
267 public ExifObject () {}
268
269 public ExifObject (IntPtr ptr)
270 {
271 handle = new HandleRef (this, ptr);
272 }
273
274 protected abstract void Cleanup ();
275
276 public void Dispose () {
277 Cleanup ();
278 System.GC.SuppressFinalize (this);
279 }
280
281 ~ExifObject ()
282 {
283 Cleanup ();
284 }
285 }
286
287 [StructLayout(LayoutKind.Sequential)]
288 internal unsafe struct _ExifContent {
289 public IntPtr entries;
290 public uint count;
291 public IntPtr parent;
292
293 public IntPtr priv;
294 }
295
296 public class ExifContent : ExifObject {
297 ExifData parent;
298 public ExifData Parent {
299 get {
300 return parent;
301 }
302 }
303
304 System.Collections.ArrayList entries;
305
306 internal ExifContent (ExifData parent, IntPtr handle) : base (handle)
307 {
308 this.parent = parent;
309 exif_content_ref (this.handle);
310 }
311
312 [DllImport ("libexif.dll")]
313 static extern void exif_content_ref (HandleRef handle);
314
315 [DllImport ("libexif.dll")]
316 static extern void exif_content_unref (HandleRef handle);
317
318 protected override void Cleanup ()
319 {
320 exif_content_unref (handle);
321 }
322
323 [DllImport ("libexif.dll")]
324 internal static extern void exif_content_remove_entry (HandleRef content, HandleRef entry);
325
326 [DllImport ("libexif.dll")]
327 internal static extern void exif_content_add_entry (HandleRef content, HandleRef entry);
328
329 public ExifEntry Lookup (Tag tag)
330 {
331 Assemble ();
332
333 foreach (ExifEntry entry in entries) {
334 if (entry.Tag == tag) {
335 return entry;
336 }
337 }
338
339 return null;
340 }
341
342 public bool Contains (ExifEntry entry)
343 {
344 Assemble ();
345
346 return entries.Contains (entry);
347 }
348
349 public ExifEntry GetEntry (Tag tag)
350 {
351 Assemble ();
352
353 ExifEntry entry = Lookup (tag);
354 if (entry == null)
355 entry = new ExifEntry (this, tag);
356
357 return entry;
358 }
359
360 public void Add (ExifEntry entry)
361 {
362 Assemble ();
363
364 entries.Add (entry);
365 // This call can recurse into this function but it protects
366 // itself by checking if it the content already contains the entry
367 entry.SetParent (this);
368 exif_content_add_entry (this.handle, entry.Handle);
369 }
370
371 public void Remove (ExifEntry entry)
372 {
373 Assemble ();
374
375 entries.Remove (entry);
376 // This call can recurse into this function but it protects
377 // itself by checking if it the content already contains the entry
378 entry.SetParent (null);
379 exif_content_remove_entry (this.handle, entry.Handle);
380 }
381
382 public ExifEntry [] GetEntries ()
383 {
384 Assemble ();
385
386 return (ExifEntry [])entries.ToArray (typeof (ExifEntry));
387 }
388
389 [DllImport ("libexif.dll")]
390 internal static unsafe extern IntPtr exif_content_foreach_entry (HandleRef content,
391 ExifContentForeachEntryFunc func,
392 IntPtr data);
393
394 internal delegate void ExifContentForeachEntryFunc (IntPtr entry_ptr, IntPtr data);
395
396 void AssembleEntry (IntPtr entry, IntPtr data)
397 {
398 entries.Add (new ExifEntry (this, entry));
399 }
400
401 ExifContentForeachEntryFunc func;
402
403 public void Assemble ()
404 {
405 if (entries == null) {
406 entries = new System.Collections.ArrayList ();
407
408 func = new ExifContentForeachEntryFunc (AssembleEntry);
409 exif_content_foreach_entry (this.Handle, func, IntPtr.Zero);
410 }
411 }
412 }
413
414
415 [StructLayout(LayoutKind.Sequential)]
416 internal struct _ExifEntry {
417 public Tag tag;
418 public int format;
419 public uint components;
420 public IntPtr data;
421 public uint size;
422
423 public IntPtr parent;
424
425 public IntPtr priv;
426 }
427
428
429 public class ExifEntry : ExifObject {
430 ExifContent parent;
431 public ExifContent Parent {
432 get {
433 unsafe {
434 if (_handle->parent != parent.Handle.Handle)
435 throw new Exception ("Invalid Object State");
436
437 return parent;
438 }
439 }
440 }
441 // Don't use this unless you know exactly what you are doing
442 internal void SetParent (ExifContent adoptor) {
443 // NOTE this api is ugly but the check prevent the parent state
444 // from getting confused. See ExifContent Add and Remove for the
445 // other half.
446 if (parent != null && parent.Contains (this))
447 parent.Remove (this);
448
449 if (adoptor != null && !adoptor.Contains (this))
450 adoptor.Add (this);
451
452 parent = adoptor;
453 }
454
455 internal ExifEntry (ExifContent parent, IntPtr native) : base (native)
456 {
457 this.handle = new HandleRef (this, native);
458 this.parent = parent;
459 exif_entry_ref (this.handle);
460 }
461
462 [DllImport ("libexif.dll")]
463 internal static extern IntPtr exif_entry_new ();
464
465 [DllImport ("libexif.dll")]
466 internal static extern void exif_entry_initialize (HandleRef handle, Tag tag);
467
468 public ExifEntry (ExifContent parent, Tag tag)
469 {
470 handle = new HandleRef (this, exif_entry_new ());
471 parent.Add (this);
472 this.Reset (tag);
473 }
474
475 public void Reset (Tag tag)
476 {
477 unsafe {
478 // Free any exsting data so that _initialize will actually set the data
479 if (_handle->data != IntPtr.Zero)
480 ExifData.free (_handle->data);
481 _handle->data = IntPtr.Zero;
482 }
483
484 exif_entry_initialize (handle, tag);
485
486 //FIXME the month string in time fields in libexif ix currently broken so we do our own.
487 if (tag == Tag.DateTime
488 || tag == Tag.DateTimeOriginal
489 || tag == Tag.DateTimeDigitized)
490 this.SetData (System.DateTime.Now);
491
492 }
493
494
495 public void Reset ()
496 {
497 Reset (Tag);
498 }
499
500 protected override void Cleanup ()
501 {
502 exif_entry_unref (this.handle);
503 }
504
505 private unsafe _ExifEntry *_handle {
506 get {
507 return (_ExifEntry *)handle.Handle;
508 }
509 }
510
511 public Tag Tag {
512 get {
513 unsafe {
514 return _handle->tag;
515 }
516 }
517 }
518
519 public ExifFormat Format {
520 get {
521 unsafe {
522 return (ExifFormat) _handle->format;
523 }
524 }
525 }
526
527 public byte [] Data {
528 get {
529 unsafe {
530 byte [] data = new byte [_handle->size];
531
532 if (data.Length > 0)
533 Marshal.Copy (_handle->data, data, 0, (int)_handle->size);
534
535 return data;
536 }
537 }
538 }
539
540 public void SetData (byte [] data, int size)
541 {
542 unsafe {
543 if (data == null || data.Length == 0)
544 throw new System.Exception ("Invalid Length");
545
546 if (_handle->data != IntPtr.Zero)
547 ExifData.free (_handle->data);
548
549 _handle->data = ExifData.malloc ((uint)data.Length);
550 Marshal.Copy (data, 0, _handle->data, data.Length);
551
552 _handle->size = (uint) data.Length;
553 // This needs to be set per type as well but
554 // we do it here as well
555 _handle->components = (uint) (data.Length / size);
556 }
557 }
558
559 public void SetData (byte []data)
560 {
561 SetData (data, 1);
562 }
563
564 public void SetData (uint s)
565 {
566 this.SetData (FSpot.BitConverter.GetBytes (s, this.ByteOrder == ByteOrder.Intel), 4);
567 }
568
569 public void SetData (ushort s)
570 {
571 this.SetData (FSpot.BitConverter.GetBytes (s, this.ByteOrder == ByteOrder.Intel), 2);
572 }
573
574 public void SetData (string value)
575 {
576 int len = System.Text.Encoding.UTF8.GetByteCount (value);
577 byte [] tmp = new byte [len + 1];
578 System.Text.Encoding.UTF8.GetBytes (value, 0, value.Length, tmp, 0);
579 tmp[len] = 0;
580 System.Console.WriteLine ("value = {0} len = {1}", value, len);
581 SetData (tmp, 1);
582 }
583
584 public void SetData (System.DateTime time)
585 {
586 SetData (time.ToString ("yyyy:MM:dd HH:mm:ss"));
587 }
588
589 private unsafe void PutBytes (byte *dest, byte *src, int count)
590 {
591 int i = 0;
592 if (System.BitConverter.IsLittleEndian == (this.ByteOrder == ByteOrder.Intel)) {
593 for (i = 0; i < count; i++) {
594 //System.Console.WriteLine ("Copying normal byte [{0}]= {1}", i, src[i]);
595 dest [i] = src [i];
596 }
597 } else {
598 for (i = 0; i < count; i++) {
599 //System.Console.WriteLine ("Copying swapped byte [{0}]= {1}", i, src[i]);
600 dest [i] = src [count - i -1];
601 }
602 }
603 }
604
605 private unsafe uint ToUInt (byte *src)
606 {
607 uint value;
608 PutBytes ((byte *)&value, (byte *)src, 4);
609 return value;
610 }
611
612 private unsafe ushort ToUShort (byte *src)
613 {
614 ushort value;
615 PutBytes ((byte *)&value, (byte *)src, 2);
616 return value;
617 }
618
619 public uint [] GetDataUInt () {
620 unsafe {
621 uint [] result = new uint [_handle->components];
622 uint *src = (uint *)_handle->data;
623 //System.Console.WriteLine ("copying {0} components", result.Length);
624 for (int i = 0; i < result.Length; i++) {
625 result [i] = ToUInt ((byte *)src);
626 //System.Console.WriteLine ("value[{0}] = {1}", i, result [i]);
627 src += i;
628 }
629
630 return result;
631 }
632 }
633
634 public ushort [] GetDataUShort () {
635 unsafe {
636 ushort [] result = new ushort [_handle->components];
637 ushort *src = (ushort *)_handle->data;
638 //System.Console.WriteLine ("copying {0} components", result.Length);
639 for (int i = 0; i < result.Length; i++) {
640 result [i] = ToUShort ((byte *)src);
641 //System.Console.WriteLine ("value[{0}] = {1}", i, result [i]);
642 src += i;
643 }
644
645 return result;
646 }
647 }
648
649
650 public int [] GetDataInt () {
651 return null;
652 }
653
654 public ByteOrder ByteOrder
655 {
656 get {
657 return parent.Parent.GetByteOrder ();
658 }
659 }
660
661 public string Description
662 {
663 get {
664 return ExifUtil.GetTagDescription (Tag);
665 }
666 }
667
668 public string Name
669 {
670 get {
671 return ExifUtil.GetTagName (Tag);
672 }
673 }
674
675 public string Title
676 {
677 get {
678 return ExifUtil.GetTagTitle (Tag);
679 }
680 }
681
682 static int fallback = 0;
683
684 // FIXME this version is only valid in libexif 0.5
685 [DllImport ("libexif.dll")]
686 internal static extern IntPtr exif_entry_get_value (HandleRef handle);
687 [DllImport ("libexif.dll")]
688 internal static extern IntPtr exif_entry_get_value_brief (HandleRef handle);
689
690 // FIXME this version is only valid in libexif 0.6
691 [DllImport ("libexif.dll")]
692 internal static extern IntPtr exif_entry_get_value (HandleRef handle, byte [] value, int maxlen);
693
694 public string Value
695 {
696 get {
697 if (fallback == 0) {
698 try {
699 exif_entry_get_value_brief (this.Handle);
700 fallback = 1;
701 } catch (EntryPointNotFoundException) {
702 fallback = -1;
703 }
704 }
705
706 if (fallback > 0)
707 return Marshal.PtrToStringAnsi (exif_entry_get_value (this.Handle));
708 else {
709 byte [] value = new byte [1024];
710 exif_entry_get_value (this.Handle, value, value.Length);
711
712 int i;
713 for (i = 0; i < value.Length; i++) {
714 if (value [i] == 0)
715 break;
716 }
717 int len = System.Math.Max (i, 0);
718 if (len == 0)
719 return null;
720
721 return System.Text.Encoding.UTF8.GetString (value, 0, len);
722 }
723 }
724 }
725
726 [DllImport ("libexif.dll")]
727 internal static extern void exif_entry_ref (HandleRef handle);
728
729 [DllImport ("libexif.dll")]
730 internal static extern void exif_entry_unref (HandleRef handle);
731 }
732
733 [StructLayout(LayoutKind.Sequential)]
734 internal struct _ExifData {
735 internal IntPtr ifd0;
736 internal IntPtr ifd1;
737 internal IntPtr ifd_exif;
738 internal IntPtr ifd_gps;
739 internal IntPtr ifd_interop;
740
741 internal IntPtr data;
742 internal int size;
743
744 internal IntPtr priv;
745 }
746
747 public class ExifData : ExifObject {
748 System.Collections.ArrayList ifds;
749
750 [DllImport ("libexif.dll")]
751 internal static extern IntPtr exif_data_new ();
752
753 public ExifData ()
754 {
755 handle = new HandleRef (this, exif_data_new ());
756 }
757
758 [DllImport ("libexif.dll")]
759 internal static extern IntPtr exif_data_new_from_file (string path);
760
761 public ExifData (string filename)
762 {
763 handle = new HandleRef (this, exif_data_new_from_file (filename));
764 }
765
766 [DllImport ("libexif.dll")]
767 internal static extern IntPtr exif_data_new_from_data (byte [] data, uint size);
768
769 public ExifData (byte [] data)
770 {
771 handle = new HandleRef (this, exif_data_new_from_data (data, (uint) data.Length));
772 }
773
774 public ExifData (byte [] data, uint size)
775 {
776 handle = new HandleRef (this, exif_data_new_from_data (data, size));
777 }
778
779 [DllImport ("libc")]
780 internal static extern void free (IntPtr address);
781
782 [DllImport ("libc")]
783 internal static extern IntPtr malloc (uint size);
784
785 [DllImport ("libexif.dll")]
786 private static extern void exif_data_save_data (HandleRef handle, out IntPtr content, out uint size);
787 public byte [] Save ()
788 {
789 Byte [] content = null;
790 uint size;
791 IntPtr data;
792 unsafe {
793 exif_data_save_data (handle, out data, out size);
794
795 content = new byte [size];
796 Marshal.Copy (data, content, 0, (int)size);
797 free (data);
798 }
799
800 System.Console.WriteLine ("Saved {0} bytes", content.Length);
801 return content;
802 }
803
804 [DllImport ("libexif.dll")]
805 internal static extern void exif_data_unref (HandleRef data);
806
807 [DllImport ("libexif.dll")]
808 internal static extern void exif_data_free (HandleRef data);
809
810 protected override void Cleanup ()
811 {
812 exif_data_unref (handle);
813 }
814
815 [DllImport ("libexif.dll")]
816 internal static extern void exif_data_dump (HandleRef data);
817
818 public void Dump ()
819 {
820 exif_data_dump (handle);
821 }
822
823 public ExifContent GetContents (Ifd ifd)
824 {
825 Assemble ();
826
827 return (ExifContent) ifds [(int)ifd];
828 }
829
830 public ExifContent [] GetContents ()
831 {
832 Assemble ();
833
834 return (ExifContent []) ifds.ToArray (typeof (ExifContent));
835 }
836
837 [DllImport("libexif.dll")]
838 internal static extern ByteOrder exif_data_get_byte_order (HandleRef handle);
839
840 public ByteOrder GetByteOrder ()
841 {
842 return exif_data_get_byte_order (handle);
843 }
844
845 internal delegate void ExifDataForeachContentFunc (IntPtr content, IntPtr data);
846
847 [DllImport ("libexif.dll")]
848 internal unsafe static extern void exif_data_foreach_content(HandleRef handle, ExifDataForeachContentFunc func, IntPtr data);
849
850 unsafe void AssembleIfds (IntPtr content, IntPtr data)
851 {
852 ifds.Add (new ExifContent (this, content));
853 }
854
855 public ExifEntry LookupFirst (Tag tag)
856 {
857 Assemble ();
858 foreach (ExifContent content in ifds) {
859 if (content == null)
860 continue;
861
862 ExifEntry entry = content.Lookup (tag);
863 if (entry != null)
864 return entry;
865 }
866 return null;
867 }
868
869 public string LookupFirstValue (Tag tag)
870 {
871 ExifEntry entry = LookupFirst (tag);
872 if (entry != null) {
873 return entry.Value;
874 }
875 return null;
876 }
877
878 public void Assemble ()
879 {
880 if (ifds == null) {
881 ifds = new System.Collections.ArrayList ();
882
883 if (handle.Handle != IntPtr.Zero)
884 exif_data_foreach_content (handle, new ExifDataForeachContentFunc (AssembleIfds), IntPtr.Zero);
885 }
886 }
887
888 byte [] empty = new byte [0];
889 public byte [] Data {
890 get {
891 unsafe {
892 _ExifData * obj = (_ExifData *) Handle.Handle;
893 byte [] result;
894
895 if (obj == null || obj->data == (IntPtr) 0)
896 result = empty;
897 else {
898 result = new byte [obj->size];
899 Marshal.Copy (obj->data, result, 0, obj->size);
900
901 }
902 return result;
903 }
904 }
905 set {
906 unsafe {
907 _ExifData * obj = (_ExifData *) Handle.Handle;
908 if (value.Length > 65533)
909 throw new System.Exception ("Thumbnail too large");
910
911 if (obj->data != IntPtr.Zero)
912 free (obj->data);
913
914 obj->data = malloc ((uint)value.Length);
915 Marshal.Copy (value, 0, obj->data, value.Length);
916 }
917 }
918 }
919 }
920 }
921
2 // Exif.cs : LibExif wrapper for FSpot
3 //
4 // Author:
5 // Larry Ewing (lewing@novell.com)
6 // Ravi Pratap (ravi@ximian.com)
7 // Miguel de Icaza (miguel@ximian.com)
8 //
9 // (C) 2002, 2004, 2005 Novell, Inc.
10 //
11
12 using System;
13 using System.Collections;
14 using System.Runtime.InteropServices;
15
16 using Mono.Unix;
17
18 namespace Exif {
19 public enum Tag {
20 InteroperabilityIndex = 0x0001,
21 InteroperabilityVersion = 0x0002,
22 ImageWidth = 0x0100,
23 ImageHeight = 0x0101,
24 BitsPersample = 0x0102,
25 Compression = 0x0103,
26 PhotometricInterpretation = 0x0106,
27 FillOrder = 0x010a,
28 DocumentName = 0x010d,
29 ImageDescription = 0x010e,
30 Make = 0x010f,
31 Model = 0x0110,
32 StripOffsets = 0x0111,
33 Orientation = 0x0112,
34 SamplesPerPixel = 0x0115,
35 RowsPerStrip = 0x0116,
36 StripByteCounts = 0x0117,
37 XResolution = 0x011a,
38 YResolution = 0x011b,
39 PlanarConfiguration = 0x011c,
40 ResolutionUnit = 0x0128,
41 TransferFunction = 0x012d,
42 Software = 0x0131,
43 DateTime = 0x0132,
44 Artist = 0x013b,
45 WhitePoint = 0x013e,
46 PrimaryChromaticities = 0x013f,
47 TransferRange = 0x0156,
48 JPEGProc = 0x0200,
49 JPEGInterchangeFormat = 0x0201,
50 JPEGInterchangeFormatLength = 0x0202,
51 YCBCRCoefficients = 0x0211,
52 YCBCRSubSampling = 0x0212,
53 YCBCRPositioning = 0x0213,
54 ReferenceBlackWhite = 0x0214,
55 RelatedImageFileFormat = 0x1000,
56 RelatedImageWidth = 0x1001,
57 RelatedImageHeight = 0x1002,
58 CFARepeatPatternDim = 0x828d,
59 CFAPattern = 0x828e,
60 BatteryLevel = 0x828f,
61 Copyright = 0x8298,
62 ExposureTime = 0x829a,
63 FNumber = 0x829d,
64 IPTCNAA = 0x83bb,
65 ExifIfdPointer = 0x8769,
66 InterColorProfile = 0x8773,
67 ExposureProgram = 0x8822,
68 SpectralSensitivity = 0x8824,
69 GPSInfoIfdPointer = 0x8825,
70 ISOSpeedRatings = 0x8827,
71 OECF = 0x8828,
72 ExifVersion = 0x9000,
73 DateTimeOriginal = 0x9003,
74 DateTimeDigitized = 0x9004,
75 ComponentsConfiguration = 0x9101,
76 CompressedBitsPerPixel = 0x9102,
77 ShutterSpeedValue = 0x9201,
78 ApertureValue = 0x9202,
79 BrightnessValue = 0x9203,
80 ExposureBiasValue = 0x9204,
81 MaxApertureValue = 0x9205,
82 SubjectDistance = 0x9206,
83 MeteringMode = 0x9207,
84 LightSource = 0x9208,
85 Flash = 0x9209,
86 FocalLength = 0x920a,
87 SubjectArea = 0x9214,
88 MakerNote = 0x927c,
89 UserComment = 0x9286,
90 SubSecTime = 0x9290,
91 SubSecTimeOriginal = 0x9291,
92 SubSecTimeDigitized = 0x9292,
93 FlashPixVersion = 0xa000,
94 ColorSpace = 0xa001,
95 PixelXDimension = 0xa002,
96 PixelYDimension = 0xa003,
97 RelatedSoundFile = 0xa004,
98 InteroperabilityIfdPointer = 0xa005,
99 FlashEnergy = 0xa20b,
100 SpatialFrequencyResponse = 0xa20c,
101 FocalPlaneXResolution = 0xa20e,
102 FocalPlaneYResolution = 0xa20f,
103 FocalPlaneResolutionUnit = 0xa210,
104 SubjectLocation = 0xa214,
105 ExposureIndex = 0xa215,
106 SensingMethod = 0xa217,
107 FileSource = 0xa300,
108 SceneType = 0xa301,
109 NewCFAPattern = 0xa302,
110 CustomRendered = 0xa401,
111 ExposureMode = 0xa402,
112 WhiteBalance = 0xa403,
113 DigitalZoomRatio = 0xa404,
114 FocalLengthIn35mmFilm = 0xa405,
115 SceneCaptureType = 0xa406,
116 GainControl = 0xa407,
117 Contrast = 0xa408,
118 Saturation = 0xa409,
119 Sharpness = 0xa40a,
120 DeviceSettingDescription = 0xa40b,
121 SubjectDistanceRange = 0xa40c,
122 ImageUniqueId = 0xa420,
123
124 // The Following IDs are not described the EXIF spec
125
126 // The XMP spec declares that XMP data should live 0x2bc when
127 // embedded in tiff images.
128 XMP = 0x02bc,
129
130 // Print Image Matching data
131 PimIfdPointer = 0xc4a5
132 }
133
134 public enum ByteOrder {
135 Motorola,
136 Intel
137 }
138
139 public enum ExifFormat {
140 Byte = 1,
141 Ascii = 2,
142 Short = 3,
143 Long = 4,
144 Rational = 5,
145 Undefined = 7,
146 Slong = 9,
147 SRational = 10
148 }
149
150 public enum Ifd {
151 Zero = 0,
152 One,
153 Exif,
154 Gps,
155 InterOperability,
156 Count
157 }
158
159 internal class ExifUtil {
160
161 [DllImport ("libexif.dll")]
162 static extern IntPtr exif_tag_get_name (Tag tag);
163
164 [DllImport ("libexif.dll")]
165 static extern IntPtr exif_tag_get_title (Tag tag);
166
167 [DllImport ("libexif.dll")]
168 static extern IntPtr exif_tag_get_description (Tag tag);
169
170 [DllImport ("libexif.dll")]
171 static extern IntPtr exif_byte_order_get_name (ByteOrder order);
172
173 [DllImport ("libexif.dll")]
174 static extern IntPtr exif_format_get_name (ExifFormat format);
175
176 [DllImport ("libexif.dll")]
177 static extern char exif_format_get_size (ExifFormat format);
178
179 [DllImport ("libexif.dll")]
180 static extern IntPtr exif_ifd_get_name (Ifd ifd);
181
182 public static string GetTagName (Tag tag)
183 {
184
185 IntPtr raw_ret = exif_tag_get_name (tag);
186 return Marshal.PtrToStringAnsi (raw_ret);
187 }
188
189 public static string GetTagTitle (Tag tag)
190 {
191 IntPtr raw_ret = exif_tag_get_title (tag);
192 return Marshal.PtrToStringAnsi (raw_ret);
193 }
194
195 public static string GetTagDescription (Tag tag)
196 {
197 IntPtr raw_ret = exif_tag_get_description (tag);
198 return Marshal.PtrToStringAnsi (raw_ret);
199 }
200
201 public static string GetByteOrderName (ByteOrder order)
202 {
203 IntPtr raw_ret = exif_byte_order_get_name (order);
204 return Marshal.PtrToStringAnsi (raw_ret);
205 }
206
207 public static string GetFormatName (ExifFormat format)
208 {
209 IntPtr raw_ret = exif_format_get_name (format);
210 return Marshal.PtrToStringAnsi (raw_ret);
211 }
212
213 public static char GetFormatSize (ExifFormat format)
214 {
215 return exif_format_get_size (format);
216 }
217
218 public static string GetIfdName (Ifd ifd)
219 {
220 IntPtr raw_ret = exif_ifd_get_name (ifd);
221 return Marshal.PtrToStringAnsi (raw_ret);
222 }
223
224 public static string GetIfdNameExtended (Ifd ifd)
225 {
226 switch (ifd) {
227 case Ifd.Zero:
228 return Catalog.GetString ("Image Directory");
229 case Ifd.One:
230 return Catalog.GetString ("Thumbnail Directory");
231 case Ifd.Exif:
232 return Catalog.GetString ("Exif Directory");
233 case Ifd.Gps:
234 return Catalog.GetString ("GPS Directory");
235 case Ifd.InterOperability:
236 return Catalog.GetString ("InterOperability Directory");
237 default:
238 return Catalog.GetString ("Unknown Directory");
239 }
240 }
241
242 public static DateTime DateTimeFromString(string dt)
243 {
244 // Exif DateTime strings are formatted as
245 // "YYYY:MM:DD HH:MM:SS"
246
247 string delimiters = " :";
248 string[] dt_data = dt.Split ( delimiters.ToCharArray(), 6 );
249 DateTime result;
250 result = new DateTime (Int32.Parse(dt_data[0]), Int32.Parse(dt_data[1]), Int32.Parse(dt_data[2]),
251 Int32.Parse(dt_data[3]), Int32.Parse(dt_data[4]), Int32.Parse(dt_data[5]));
252
253 return result;
254 }
255
256 }
257
258 public abstract class ExifObject : IDisposable {
259 protected HandleRef handle;
260
261 public HandleRef Handle {
262 get {
263 return handle;
264 }
265 }
266
267 public ExifObject () {}
268
269 public ExifObject (IntPtr ptr)
270 {
271 handle = new HandleRef (this, ptr);
272 }
273
274 protected abstract void Cleanup ();
275
276 public void Dispose () {
277 Cleanup ();
278 System.GC.SuppressFinalize (this);
279 }
280
281 ~ExifObject ()
282 {
283 Cleanup ();
284 }
285 }
286
287 [StructLayout(LayoutKind.Sequential)]
288 internal unsafe struct _ExifContent {
289 public IntPtr entries;
290 public uint count;
291 public IntPtr parent;
292
293 public IntPtr priv;
294 }
295
296 public class ExifContent : ExifObject {
297 ExifData parent;
298 public ExifData Parent {
299 get {
300 return parent;
301 }
302 }
303
304 System.Collections.ArrayList entries;
305
306 internal ExifContent (ExifData parent, IntPtr handle) : base (handle)
307 {
308 this.parent = parent;
309 exif_content_ref (this.handle);
310 }
311
312 [DllImport ("libexif.dll")]
313 static extern void exif_content_ref (HandleRef handle);
314
315 [DllImport ("libexif.dll")]
316 static extern void exif_content_unref (HandleRef handle);
317
318 protected override void Cleanup ()
319 {
320 exif_content_unref (handle);
321 }
322
323 [DllImport ("libexif.dll")]
324 internal static extern void exif_content_remove_entry (HandleRef content, HandleRef entry);
325
326 [DllImport ("libexif.dll")]
327 internal static extern void exif_content_add_entry (HandleRef content, HandleRef entry);
328
329 public ExifEntry Lookup (Tag tag)
330 {
331 Assemble ();
332
333 foreach (ExifEntry entry in entries) {
334 if (entry.Tag == tag) {
335 return entry;
336 }
337 }
338
339 return null;
340 }
341
342 public bool Contains (ExifEntry entry)
343 {
344 Assemble ();
345
346 return entries.Contains (entry);
347 }
348
349 public ExifEntry GetEntry (Tag tag)
350 {
351 Assemble ();
352
353 ExifEntry entry = Lookup (tag);
354 if (entry == null)
355 entry = new ExifEntry (this, tag);
356
357 return entry;
358 }
359
360 public void Add (ExifEntry entry)
361 {
362 Assemble ();
363
364 entries.Add (entry);
365 // This call can recurse into this function but it protects
366 // itself by checking if it the content already contains the entry
367 entry.SetParent (this);
368 exif_content_add_entry (this.handle, entry.Handle);
369 }
370
371 public void Remove (ExifEntry entry)
372 {
373 Assemble ();
374
375 entries.Remove (entry);
376 // This call can recurse into this function but it protects
377 // itself by checking if it the content already contains the entry
378 entry.SetParent (null);
379 exif_content_remove_entry (this.handle, entry.Handle);
380 }
381
382 public ExifEntry [] GetEntries ()
383 {
384 Assemble ();
385
386 return (ExifEntry [])entries.ToArray (typeof (ExifEntry));
387 }
388
389 [DllImport ("libexif.dll")]
390 internal static unsafe extern IntPtr exif_content_foreach_entry (HandleRef content,
391 ExifContentForeachEntryFunc func,
392 IntPtr data);
393
394 internal delegate void ExifContentForeachEntryFunc (IntPtr entry_ptr, IntPtr data);
395
396 void AssembleEntry (IntPtr entry, IntPtr data)
397 {
398 entries.Add (new ExifEntry (this, entry));
399 }
400
401 ExifContentForeachEntryFunc func;
402
403 public void Assemble ()
404 {
405 if (entries == null) {
406 entries = new System.Collections.ArrayList ();
407
408 func = new ExifContentForeachEntryFunc (AssembleEntry);
409 exif_content_foreach_entry (this.Handle, func, IntPtr.Zero);
410 }
411 }
412 }
413
414
415 [StructLayout(LayoutKind.Sequential)]
416 internal struct _ExifEntry {
417 public Tag tag;
418 public int format;
419 public uint components;
420 public IntPtr data;
421 public uint size;
422
423 public IntPtr parent;
424
425 public IntPtr priv;
426 }
427
428
429 public class ExifEntry : ExifObject {
430 ExifContent parent;
431 public ExifContent Parent {
432 get {
433 unsafe {
434 if (_handle->parent != parent.Handle.Handle)
435 throw new Exception ("Invalid Object State");
436
437 return parent;
438 }
439 }
440 }
441 // Don't use this unless you know exactly what you are doing
442 internal void SetParent (ExifContent adoptor) {
443 // NOTE this api is ugly but the check prevent the parent state
444 // from getting confused. See ExifContent Add and Remove for the
445 // other half.
446 if (parent != null && parent.Contains (this))
447 parent.Remove (this);
448
449 if (adoptor != null && !adoptor.Contains (this))
450 adoptor.Add (this);
451
452 parent = adoptor;
453 }
454
455 internal ExifEntry (ExifContent parent, IntPtr native) : base (native)
456 {
457 this.handle = new HandleRef (this, native);
458 this.parent = parent;
459 exif_entry_ref (this.handle);
460 }
461
462 [DllImport ("libexif.dll")]
463 internal static extern IntPtr exif_entry_new ();
464
465 [DllImport ("libexif.dll")]
466 internal static extern void exif_entry_initialize (HandleRef handle, Tag tag);
467
468 public ExifEntry (ExifContent parent, Tag tag)
469 {
470 handle = new HandleRef (this, exif_entry_new ());
471 parent.Add (this);
472 this.Reset (tag);
473 }
474
475 public void Reset (Tag tag)
476 {
477 unsafe {
478 // Free any exsting data so that _initialize will actually set the data
479 if (_handle->data != IntPtr.Zero)
480 ExifData.free (_handle->data);
481 _handle->data = IntPtr.Zero;
482 }
483
484 exif_entry_initialize (handle, tag);
485
486 //FIXME the month string in time fields in libexif ix currently broken so we do our own.
487 if (tag == Tag.DateTime
488 || tag == Tag.DateTimeOriginal
489 || tag == Tag.DateTimeDigitized)
490 this.SetData (System.DateTime.Now);
491
492 }
493
494
495 public void Reset ()
496 {
497 Reset (Tag);
498 }
499
500 protected override void Cleanup ()
501 {
502 exif_entry_unref (this.handle);
503 }
504
505 private unsafe _ExifEntry *_handle {
506 get {
507 return (_ExifEntry *)handle.Handle;
508 }
509 }
510
511 public Tag Tag {
512 get {
513 unsafe {
514 return _handle->tag;
515 }
516 }
517 }
518
519 public ExifFormat Format {
520 get {
521 unsafe {
522 return (ExifFormat) _handle->format;
523 }
524 }
525 }
526
527 public byte [] Data {
528 get {
529 unsafe {
530 byte [] data = new byte [_handle->size];
531
532 if (data.Length > 0)
533 Marshal.Copy (_handle->data, data, 0, (int)_handle->size);
534
535 return data;
536 }
537 }
538 }
539
540 public void SetData (byte [] data, int size)
541 {
542 unsafe {
543 if (data == null || data.Length == 0)
544 throw new System.Exception ("Invalid Length");
545
546 if (_handle->data != IntPtr.Zero)
547 ExifData.free (_handle->data);
548
549 _handle->data = ExifData.malloc ((uint)data.Length);
550 Marshal.Copy (data, 0, _handle->data, data.Length);
551
552 _handle->size = (uint) data.Length;
553 // This needs to be set per type as well but
554 // we do it here as well
555 _handle->components = (uint) (data.Length / size);
556 }
557 }
558
559 public void SetData (byte []data)
560 {
561 SetData (data, 1);
562 }
563
564 public void SetData (uint s)
565 {
566 this.SetData (FSpot.BitConverter.GetBytes (s, this.ByteOrder == ByteOrder.Intel), 4);
567 }
568
569 public void SetData (ushort s)
570 {
571 this.SetData (FSpot.BitConverter.GetBytes (s, this.ByteOrder == ByteOrder.Intel), 2);
572 }
573
574 public void SetData (string value)
575 {
576 int len = System.Text.Encoding.UTF8.GetByteCount (value);
577 byte [] tmp = new byte [len + 1];
578 System.Text.Encoding.UTF8.GetBytes (value, 0, value.Length, tmp, 0);
579 tmp[len] = 0;
580 System.Console.WriteLine ("value = {0} len = {1}", value, len);
581 SetData (tmp, 1);
582 }
583
584 public void SetData (System.DateTime time)
585 {
586 SetData (time.ToString ("yyyy:MM:dd HH:mm:ss"));
587 }
588
589 private unsafe void PutBytes (byte *dest, byte *src, int count)
590 {
591 int i = 0;
592 if (System.BitConverter.IsLittleEndian == (this.ByteOrder == ByteOrder.Intel)) {
593 for (i = 0; i < count; i++) {
594 //System.Console.WriteLine ("Copying normal byte [{0}]= {1}", i, src[i]);
595 dest [i] = src [i];
596 }
597 } else {
598 for (i = 0; i < count; i++) {
599 //System.Console.WriteLine ("Copying swapped byte [{0}]= {1}", i, src[i]);
600 dest [i] = src [count - i -1];
601 }
602 }
603 }
604
605 private unsafe uint ToUInt (byte *src)
606 {
607 uint value;
608 PutBytes ((byte *)&value, (byte *)src, 4);
609 return value;
610 }
611
612 private unsafe ushort ToUShort (byte *src)
613 {
614 ushort value;
615 PutBytes ((byte *)&value, (byte *)src, 2);
616 return value;
617 }
618
619 public uint [] GetDataUInt () {
620 unsafe {
621 uint [] result = new uint [_handle->components];
622 uint *src = (uint *)_handle->data;
623 //System.Console.WriteLine ("copying {0} components", result.Length);
624 for (int i = 0; i < result.Length; i++) {
625 result [i] = ToUInt ((byte *)src);
626 //System.Console.WriteLine ("value[{0}] = {1}", i, result [i]);
627 src += i;
628 }
629
630 return result;
631 }
632 }
633
634 public ushort [] GetDataUShort () {
635 unsafe {
636 ushort [] result = new ushort [_handle->components];
637 ushort *src = (ushort *)_handle->data;
638 //System.Console.WriteLine ("copying {0} components", result.Length);
639 for (int i = 0; i < result.Length; i++) {
640 result [i] = ToUShort ((byte *)src);
641 //System.Console.WriteLine ("value[{0}] = {1}", i, result [i]);
642 src += i;
643 }
644
645 return result;
646 }
647 }
648
649
650 public int [] GetDataInt () {
651 return null;
652 }
653
654 public ByteOrder ByteOrder
655 {
656 get {
657 return parent.Parent.GetByteOrder ();
658 }
659 }
660
661 public string Description
662 {
663 get {
664 return ExifUtil.GetTagDescription (Tag);
665 }
666 }
667
668 public string Name
669 {
670 get {
671 return ExifUtil.GetTagName (Tag);
672 }
673 }
674
675 public string Title
676 {
677 get {
678 return ExifUtil.GetTagTitle (Tag);
679 }
680 }
681
682 static int fallback = 0;
683
684 // FIXME this version is only valid in libexif 0.5
685 [DllImport ("libexif.dll")]
686 internal static extern IntPtr exif_entry_get_value (HandleRef handle);
687 [DllImport ("libexif.dll")]
688 internal static extern IntPtr exif_entry_get_value_brief (HandleRef handle);
689
690 // FIXME this version is only valid in libexif 0.6
691 [DllImport ("libexif.dll")]
692 internal static extern IntPtr exif_entry_get_value (HandleRef handle, byte [] value, int maxlen);
693
694 public string Value
695 {
696 get {
697 if (fallback == 0) {
698 try {
699 exif_entry_get_value_brief (this.Handle);
700 fallback = 1;
701 } catch (EntryPointNotFoundException) {
702 fallback = -1;
703 }
704 }
705
706 if (fallback > 0)
707 return Marshal.PtrToStringAnsi (exif_entry_get_value (this.Handle));
708 else {
709 byte [] value = new byte [1024];
710 exif_entry_get_value (this.Handle, value, value.Length);
711
712 int i;
713 for (i = 0; i < value.Length; i++) {
714 if (value [i] == 0)
715 break;
716 }
717 int len = System.Math.Max (i, 0);
718 if (len == 0)
719 return null;
720
721 return System.Text.Encoding.UTF8.GetString (value, 0, len);
722 }
723 }
724 }
725
726 [DllImport ("libexif.dll")]
727 internal static extern void exif_entry_ref (HandleRef handle);
728
729 [DllImport ("libexif.dll")]
730 internal static extern void exif_entry_unref (HandleRef handle);
731 }
732
733 [StructLayout(LayoutKind.Sequential)]
734 internal struct _ExifData {
735 internal IntPtr ifd0;
736 internal IntPtr ifd1;
737 internal IntPtr ifd_exif;
738 internal IntPtr ifd_gps;
739 internal IntPtr ifd_interop;
740
741 internal IntPtr data;
742 internal int size;
743
744 internal IntPtr priv;
745 }
746
747 public class ExifData : ExifObject {
748 System.Collections.ArrayList ifds;
749
750 [DllImport ("libexif.dll")]
751 internal static extern IntPtr exif_data_new ();
752
753 public ExifData ()
754 {
755 handle = new HandleRef (this, exif_data_new ());
756 }
757
758 [DllImport ("libexif.dll")]
759 internal static extern IntPtr exif_data_new_from_file (string path);
760
761 public ExifData (string filename)
762 {
763 handle = new HandleRef (this, exif_data_new_from_file (filename));
764 }
765
766 [DllImport ("libexif.dll")]
767 internal static extern IntPtr exif_data_new_from_data (byte [] data, uint size);
768
769 public ExifData (byte [] data)
770 {
771 handle = new HandleRef (this, exif_data_new_from_data (data, (uint) data.Length));
772 }
773
774 public ExifData (byte [] data, uint size)
775 {
776 handle = new HandleRef (this, exif_data_new_from_data (data, size));
777 }
778
779 [DllImport ("libc")]
780 internal static extern void free (IntPtr address);
781
782 [DllImport ("libc")]
783 internal static extern IntPtr malloc (uint size);
784
785 [DllImport ("libexif.dll")]
786 private static extern void exif_data_save_data (HandleRef handle, out IntPtr content, out uint size);
787 public byte [] Save ()
788 {
789 Byte [] content = null;
790 uint size;
791 IntPtr data;
792 unsafe {
793 exif_data_save_data (handle, out data, out size);
794
795 content = new byte [size];
796 Marshal.Copy (data, content, 0, (int)size);
797 free (data);
798 }
799
800 System.Console.WriteLine ("Saved {0} bytes", content.Length);
801 return content;
802 }
803
804 [DllImport ("libexif.dll")]
805 internal static extern void exif_data_unref (HandleRef data);
806
807 [DllImport ("libexif.dll")]
808 internal static extern void exif_data_free (HandleRef data);
809
810 protected override void Cleanup ()
811 {
812 exif_data_unref (handle);
813 }
814
815 [DllImport ("libexif.dll")]
816 internal static extern void exif_data_dump (HandleRef data);
817
818 public void Dump ()
819 {
820 exif_data_dump (handle);
821 }
822
823 public ExifContent GetContents (Ifd ifd)
824 {
825 Assemble ();
826
827 return (ExifContent) ifds [(int)ifd];
828 }
829
830 public ExifContent [] GetContents ()
831 {
832 Assemble ();
833
834 return (ExifContent []) ifds.ToArray (typeof (ExifContent));
835 }
836
837 [DllImport("libexif.dll")]
838 internal static extern ByteOrder exif_data_get_byte_order (HandleRef handle);
839
840 public ByteOrder GetByteOrder ()
841 {
842 return exif_data_get_byte_order (handle);
843 }
844
845 internal delegate void ExifDataForeachContentFunc (IntPtr content, IntPtr data);
846
847 [DllImport ("libexif.dll")]
848 internal unsafe static extern void exif_data_foreach_content(HandleRef handle, ExifDataForeachContentFunc func, IntPtr data);
849
850 unsafe void AssembleIfds (IntPtr content, IntPtr data)
851 {
852 ifds.Add (new ExifContent (this, content));
853 }
854
855 public ExifEntry LookupFirst (Tag tag)
856 {
857 Assemble ();
858 foreach (ExifContent content in ifds) {
859 if (content == null)
860 continue;
861
862 ExifEntry entry = content.Lookup (tag);
863 if (entry != null)
864 return entry;
865 }
866 return null;
867 }
868
869 public string LookupFirstValue (Tag tag)
870 {
871 ExifEntry entry = LookupFirst (tag);
872 if (entry != null) {
873 return entry.Value;
874 }
875 return null;
876 }
877
878 public void Assemble ()
879 {
880 if (ifds == null) {
881 ifds = new System.Collections.ArrayList ();
882
883 if (handle.Handle != IntPtr.Zero)
884 exif_data_foreach_content (handle, new ExifDataForeachContentFunc (AssembleIfds), IntPtr.Zero);
885 }
886 }
887
888 byte [] empty = new byte [0];
889 public byte [] Data {
890 get {
891 unsafe {
892 _ExifData * obj = (_ExifData *) Handle.Handle;
893 byte [] result;
894
895 if (obj == null || obj->data == (IntPtr) 0)
896 result = empty;
897 else {
898 result = new byte [obj->size];
899 Marshal.Copy (obj->data, result, 0, obj->size);
900
901 }
902 return result;
903 }
904 }
905 set {
906 unsafe {
907 _ExifData * obj = (_ExifData *) Handle.Handle;
908 if (value.Length > 65533)
909 throw new System.Exception ("Thumbnail too large");
910
911 if (obj->data != IntPtr.Zero)
912 free (obj->data);
913
914 obj->data = malloc ((uint)value.Length);
915 Marshal.Copy (value, 0, obj->data, value.Length);
916 }
917 }
918 }
919 }
920 }
921
哲学管理(学)人生, 文学艺术生活, 自动(计算机学)物理(学)工作, 生物(学)化学逆境, 历史(学)测绘(学)时间, 经济(学)数学金钱(理财), 心理(学)医学情绪, 诗词美容情感, 美学建筑(学)家园, 解构建构(分析)整合学习, 智商情商(IQ、EQ)运筹(学)生存.---Geovin Du(涂聚文)