2008-10-07 20 views
36

En Windows XP, "FileInfo.LastWriteTime" devolverá la fecha en que se tomó una fotografía, independientemente de cuántas veces se movió el archivo en el sistema de archivos.¿Cómo puedo saber cuándo se tomó una foto en C# corriendo en Vista?

En Vista, en cambio, devuelve la fecha de copia de la imagen de la cámara.

¿Cómo puedo saber cuándo se toma una foto en Vista? En Windows Explorer este campo se conoce como "Fecha de toma".

Respuesta

78

Aquí está lo más rápido y limpio que pueda conseguirlo. Al usar FileStream, puedes decirle a GDI + que no cargue toda la imagen para su verificación. Corre más de 10 veces más rápido en mi máquina.

//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); 
     } 
    } 

Y sí, el ID correcto es 36867, no 306.

Los otros proyectos de código abierto por debajo deberían tomar nota de esto. ¡es un GRAN impacto de rendimiento al procesar miles de archivos!

+1

Después de algunas pruebas descubrí que su respuesta es la mejor. Gracias. – Sergio

+4

Ahora solo si hubiera hecho una comprobación para ver si existe primero. Siempre hay una posibilidad de que esta propiedad no lo haga. –

+6

¡Gran solución! El control de propiedad es importante. Si agrega if (myImage.PropertyIdList.Any (x => x == 36867)) como su verificación, ¡funciona de maravilla! –

5

Con WPF y C# se puede obtener la propiedad tomada Date utilizando la clase BitmapMetadata:

MSDN - BitmapMetada

WPF and BitmapMetadata

+0

¿Puedo usar BitmapMetadata con Window.Forms o solo es WPF? (Obteniendo mensajes de error extraños de Visual Studio 2008) – sepang

+0

O use [mi biblioteca] (http://stackoverflow.com/a/39839380/24874) que tiene una API más simple y se ejecuta alrededor de 17 veces más rápido que estas API de WPF (o 30 veces más rápido si solo quiere Exif). –

1

que tendrá que comprobar la información EXIF ​​de la imagen. No creo que con las funciones regulares de .Net sabrá cuando se tomó la foto.

puede ser que consiga un poco complicado ...

1

Habrá datos EXIF ​​incrustados en la imagen. Hay un montón de ejemplos en la web si busca EXIF ​​y C#.

2

en Windows XP "FileInfo.LastWriteTime" devolverá la fecha es una imagen tomada - sin importar cuántas veces el archivo se mueve alrededor en el sistema de archivos .

Tengo grandes dudas de que XP realmente estaba haciendo eso. Lo más probable es que la herramienta que utilizó para copiar la imagen de la cámara a su disco duro restableció la fecha de modificación del archivo a la Fecha de toma de la imagen.

+0

La herramienta fue Windows Explorer. – sepang

+0

ah ... Eso podría explicarlo. La cámara es una computadora pequeña con un sistema de archivos. Está "escrito en el disco" cuando se toma la foto. Explorer mantener esos cuando se copia. –

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

ACTUALMENTE, 306 es el último identificador de fecha MODIFICADO ... Lo intenté y estaba MUY CERCA ... Sin embargo, al mirar TODAS las identificaciones de propiedad, y al arrojar a un archivo de texto, encontré que la ID 36867 era la fecha tomada (aunque 36868 también tiene el mismo valor de Fecha de toma, por lo que no estoy seguro de cuál fue el que) – DRapp

+0

la respuesta anterior debe cambiarse a la respuesta en cuanto a la velocidad para obtener el EXIFG si existe. Este método funciona, pero es lento, ¡especialmente en lote! – 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

Esto es, literalmente, un duplicado de la respuesta de @kDar, con un poco de manejo de errores ... – Mark

4

mantenía una simple open-source library desde 2002 para extraer metadatos de los archivos de imagen/vídeo.

// 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); 

En mis puntos de referencia, este código se ejecuta más de 12 veces más rápido que Image.GetPropertyItem, y alrededor de 17 veces más rápido que la API de WPF JpegBitmapDecoder/BitmapMetadata.

Hay una tonelada de información adicional disponible de la biblioteca como ajustes de la cámara (F-stop, ISO, velocidad de obturación, modo de flash, distancia focal, ...), propiedades de la imagen (dimensiones, configuraciones de píxeles) y otras cosas como posiciones de GPS, palabras clave, información de copyright, etc.

Si solo está interesado en los metadatos, usar esta biblioteca es muy rápido ya que no decodifica la imagen (es decir, mapa de bits).Puede escanear miles de imágenes en unos segundos si tiene un almacenamiento lo suficientemente rápido.

ImageMetadataReader comprende muchos tipos de archivos (JPEG, PNG, GIF, BMP, TIFF, PCX, WebP, ICO, ...). Si sabe que usted está tratando con JPEG, y que sólo se desea que los datos Exif, entonces usted puede hacer el proceso más rápido de lo siguiente:

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

La bibliotecametadatos extractora está disponible a través de NuGet y code's on GitHub. Gracias a todos los colaboradores increíbles que han mejorado la biblioteca y enviado imágenes de prueba a lo largo de los años.

+0

Drew, ¡estoy de vuelta! Ahora tengo el código para convertir RAW a Tiff, pero mi Image.GetPropertyItem no tiene fecha usando 36867. ¿Su código hará Tiffs y Raws? – JustJohn

+0

Y. . . . rodillo de tambor. . . . ¡se instaló impecablemente según su Nugetter y usando el código de arriba en su anwer devolvió la fecha de PhotoTaken para un archivo .CR2 (Canon)! Por supuesto, tuvo que hacer clic en varias soluciones posibles para que los usuarios se pusieran en la parte superior, pero VS 2017 cuida de ti. – JustJohn

+0

Me alegra oír que funcionó para ti. –

Cuestiones relacionadas