2008-10-07 8 views
36

In Windows XP gibt "FileInfo.LastWriteTime" das Datum zurück, an dem ein Bild aufgenommen wurde - unabhängig davon, wie oft die Datei im Dateisystem verschoben wird.Wie kann ich herausfinden, wann ein Bild in C# auf Vista aufgenommen wurde?

In Vista wird stattdessen das Datum zurückgegeben, an dem das Bild von der Kamera kopiert wird.

Wie kann ich herausfinden, wenn ein Bild in Vista aufgenommen wird? Im Windows Explorer wird dieses Feld als "Date Taken" bezeichnet.

Antwort

78

Hier ist so schnell und sauber wie Sie es bekommen können. Mithilfe von FileStream können Sie GDI + mitteilen, dass das gesamte Bild nicht zur Überprüfung geladen werden soll. Es läuft über 10x so schnell auf meiner Maschine.

//we init this once so that if the function is repeatedly called 
    //it isn't stressing the garbage man 
    private static Regex r = new Regex(":"); 

    //retrieves the datetime WITHOUT loading the whole image 
    public static DateTime GetDateTakenFromImage(string path) 
    { 
     using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) 
     using (Image myImage = Image.FromStream(fs, false, false)) 
     { 
      PropertyItem propItem = myImage.GetPropertyItem(36867); 
      string dateTaken = r.Replace(Encoding.UTF8.GetString(propItem.Value), "-", 2); 
      return DateTime.Parse(dateTaken); 
     } 
    } 

Und ja, die richtige ID ist 36867, nicht 306.

Die anderen Open-Source-Projekte unter sollten zur Kenntnis nehmen. Es ist ein riesiger Performance-Hit bei der Verarbeitung von Tausenden von Dateien!

+1

Nach ein paar Tests habe ich herausgefunden, dass deine Antwort die beste ist. Vielen Dank. – Sergio

+4

Jetzt nur, wenn Sie eine Überprüfung durchgeführt hätten, um zu sehen, ob sie zuerst existiert. Es gibt immer eine Chance, die diese Eigenschaft nicht hat. –

+6

Große Lösung! Die Eigenschaftsprüfung ist wichtig. Wenn Sie hinzufügen, wenn (myImage.PropertyIdList.Any (x => x == 36867)) als Ihre Überprüfung funktioniert es großartig! –

5

mit WPF und C# Sie das Aufnahmedatum Eigenschaft erhalten können die BitmapMetadata-Klasse:

MSDN - BitmapMetada

WPF and BitmapMetadata

+0

Kann ich BitmapMetadata mit Window.Forms verwenden oder ist es nur WPF? (seltsame Fehlermeldungen von Visual Studio 2008 erhalten) – sepang

+0

Oder verwenden Sie [meine Bibliothek] (http://stackoverflow.com/a/39839380/24874), die eine einfachere API hat und etwa 17 mal schneller als diese WPF-APIs (oder 30 mal schneller wenn du nur Exif willst). –

1

Sie werden die EXIF-Informationen aus dem Bild haben zu überprüfen. Ich glaube nicht, dass man bei regulären .Net-Funktionen weiß, wann das Bild aufgenommen wurde.

Es könnte ein wenig kompliziert ...

1

bekommt Es wird in dem Bild eingebettet EXIF-Daten sein. Es gibt eine Menge Beispiele im Internet, wenn Sie nach EXIF ​​und C# suchen.

2

in Windows XP „FileInfo.LastWriteTime“ wird das Datum ein Bild zurückzukehren genommen - unabhängig davon, wie oft die Datei um im Dateisystem verschoben wird.

Ich habe große Zweifel, dass XP tatsächlich das getan hat. Wahrscheinlich hat das Werkzeug, mit dem Sie das Bild von der Kamera auf Ihre Festplatte kopiert haben, das Dateiänderungsdatum auf das Aufnahmedatum des Bildes zurückgesetzt.

+0

Das Tool war Windows Explorer. – sepang

+0

ah .. Das könnte es erklären. Die Kamera ist ein kleiner Computer mit einem Dateisystem. Es wird "auf die Festplatte geschrieben", wenn das Foto aufgenommen wird. Explorer behält diese beim Kopieren bei. –

10
Image myImage = Image.FromFile(@"C:\temp\IMG_0325.JPG"); 
PropertyItem propItem = myImage.GetPropertyItem(306); 
DateTime dtaken; 

//Convert date taken metadata to a DateTime object 
string sdate = Encoding.UTF8.GetString(propItem.Value).Trim(); 
string secondhalf = sdate.Substring(sdate.IndexOf(" "), (sdate.Length - sdate.IndexOf(" "))); 
string firsthalf = sdate.Substring(0, 10); 
firsthalf = firsthalf.Replace(":", "-"); 
sdate = firsthalf + secondhalf; 
dtaken = DateTime.Parse(sdate); 
+1

AKTUELL, 306 ist der letzte MODIFIED Datumsbezeichner ... Ich versuchte es und es war SEHR SCHLIESSEN ... Allerdings, wenn ich ALLE Property IDs betrachtete und in eine Textdatei pumpte, fand ich, dass ID 36867 das Datum war, das ich genommen habe 36868 hat auch das gleiche Datum Taken Wert, so dass ich nicht positiv war, was war) – DRapp

+0

die Antwort oben sollte auf die Antwort so weit wie die Geschwindigkeit des Erhaltens der EXIFG geändert werden, wenn es existiert. Diese Methode funktioniert, ist aber langsam - vor allem im Batch! – TheSoftwareJedi

0
//retrieves the datetime WITHOUT loading the whole image 
    public static DateTime GetDateTakenFromImage(string path) 
    { 
     using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) 
     using (Image myImage = Image.FromStream(fs, false, false)) 
     { 
      PropertyItem propItem = null; 
      try 
      { 
       propItem = myImage.GetPropertyItem(36867); 
      } 
      catch { } 
      if (propItem != null) 
      { 
       string dateTaken = r.Replace(Encoding.UTF8.GetString(propItem.Value), "-", 2); 
       return DateTime.Parse(dateTaken); 
      } 
      else 
       return new FileInfo(path).LastWriteTime; 
     } 
    } 
+0

Dies ist buchstäblich ein Duplikat von @ kDars Antwort, mit ein bisschen Fehlerbehandlung ... – Mark

4

beibehalten ich ein simple open-source library seit 2002 für Metadaten aus Bild/Video-Dateien zu extrahieren.

// Read all metadata from the image 
var directories = ImageMetadataReader.ReadMetadata(stream); 

// Find the so-called Exif "SubIFD" (which may be null) 
var subIfdDirectory = directories.OfType<ExifSubIfdDirectory>().FirstOrDefault(); 

// Read the DateTime tag value 
var dateTime = subIfdDirectory?.GetDateTime(ExifDirectoryBase.TagDateTimeOriginal); 

In meiner Benchmarks, läuft dieser Code über 12-mal schneller als Image.GetPropertyItem, und rund 17 mal schneller als die WPF JpegBitmapDecoder/BitmapMetadata API.

Es gibt eine Tonne zusätzlicher Informationen aus der Bibliothek wie Kameraeinstellungen (F-Stop, ISO, Verschlusszeit, Blitzmodus, Brennweite, ...), Bildeigenschaften (Abmessungen, Pixelkonfigurationen) und andere Dinge wie GPS-Positionen, Stichwörter, Copyright-Informationen, usw.

Wenn Sie nur an den Metadaten interessiert sind, dann ist die Verwendung dieser Bibliothek sehr schnell, da das Bild nicht dekodiert wird (zB Bitmap).Sie können Tausende von Bildern in wenigen Sekunden scannen, wenn Sie schnell genug Speicherplatz haben.

ImageMetadataReader versteht viele Dateitypen (JPEG, PNG, GIF, BMP, TIFF, PCX, WebP, ICO, ...). Wenn Sie wissen, , die Sie mit JPEG zu tun haben, und Sie nur wollen Exif-Daten, dann können Sie den Prozess machen noch schneller mit den folgenden:

var directories = JpegMetadataReader.ReadMetadata(stream, new[] { new ExifReader() }); 

Die Metadaten-Extraktor Bibliothek ist verfügbar über NuGet und die code's on GitHub. Vielen Dank an all die großartigen Mitwirkenden, die im Laufe der Jahre die Bibliothek verbessert und Testbilder eingereicht haben.

+0

Drew, ich bin zurück! Ich habe jetzt Code, um RAW zu Tiff zu konvertieren, aber mein Image.GetPropertyItem hat kein Datum, das mit 36867 genommen wird. Wird Ihr Code Tiffs und Raws tun? – JustJohn

+0

Und. . . . Trommelwirbel. . . . Es wurde fehlerfrei installiert, so wie es in Ihrem Nugetter der Fall ist, und mit dem obigen Code in Ihrer Antwort wurde das PhotoTaken-Datum für eine .CR2-Datei (Canon) zurückgegeben! Natürlich musste ich auf einige mögliche Fixes klicken, um die Usings an die Spitze zu bringen, aber VS 2017 babysits Sie. – JustJohn

+0

Ich bin froh zu hören, dass es für Sie funktioniert hat. –

Verwandte Themen