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