c# - online - metapicz
determinar si el archivo es una imagen (11)
Estoy recorriendo un directorio y copiando todos los archivos. En este momento estoy haciendo string.EndsWith comprueba ".jpg" o ".png", etc. .
¿Hay alguna manera más elegante de determinar si un archivo es una imagen (cualquier tipo de imagen) sin el cheque hacky anterior?
Echa un vistazo a System.IO.Path.GetExtension
Aquí hay una muestra rápida.
public static readonly List<string> ImageExtensions = new List<string> { ".JPG", ".JPE", ".BMP", ".GIF", ".PNG" };
private void button_Click(object sender, RoutedEventArgs e)
{
var folder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var files = Directory.GetFiles(folder);
foreach(var f in files)
{
if (ImageExtensions.Contains(Path.GetExtension(f).ToUpperInvariant()))
{
// process image
}
}
}
Esto examinará los primeros bytes de un archivo y determinará si se trata de una imagen.
using System.Collections.Generic;
using System.IO;
using System.Linq;
public static class Extension
{
public static bool IsImage(this Stream stream)
{
stream.Seek(0, SeekOrigin.Begin);
List<string> jpg = new List<string> { "FF", "D8" };
List<string> bmp = new List<string> { "42", "4D" };
List<string> gif = new List<string> { "47", "49", "46" };
List<string> png = new List<string> { "89", "50", "4E", "47", "0D", "0A", "1A", "0A" };
List<List<string>> imgTypes = new List<List<string>> { jpg, bmp, gif, png };
List<string> bytesIterated = new List<string>();
for (int i = 0; i < 8; i++)
{
string bit = stream.ReadByte().ToString("X2");
bytesIterated.Add(bit);
bool isImage = imgTypes.Any(img => !img.Except(bytesIterated).Any());
if (isImage)
{
return true;
}
}
return false;
}
}
Editar
He hecho algunos cambios a lo anterior para permitirle agregar sus propias imágenes si lo necesitaba, también quité colecciones que no eran necesarias para empezar. También agregué una sobrecarga al aceptar un parámetro de out
de tipo string
, estableciendo el valor para el tipo de imagen de la que se compone la secuencia.
public static class Extension
{
static Extension()
{
ImageTypes = new Dictionary<string, string>();
ImageTypes.Add("FFD8","jpg");
ImageTypes.Add("424D","bmp");
ImageTypes.Add("474946","gif");
ImageTypes.Add("89504E470D0A1A0A","png");
}
/// <summary>
/// <para> Registers a hexadecimal value used for a given image type </para>
/// <param name="imageType"> The type of image, example: "png" </param>
/// <param name="uniqueHeaderAsHex"> The type of image, example: "89504E470D0A1A0A" </param>
/// </summary>
public static void RegisterImageHeaderSignature(string imageType, string uniqueHeaderAsHex)
{
Regex validator = new Regex(@"^[A-F0-9]+$", RegexOptions.CultureInvariant);
uniqueHeaderAsHex = uniqueHeaderAsHex.Replace(" ", "");
if (string.IsNullOrWhiteSpace(imageType)) throw new ArgumentNullException("imageType");
if (string.IsNullOrWhiteSpace(uniqueHeaderAsHex)) throw new ArgumentNullException("uniqueHeaderAsHex");
if (uniqueHeaderAsHex.Length % 2 != 0) throw new ArgumentException ("Hexadecimal value is invalid");
if (!validator.IsMatch(uniqueHeaderAsHex)) throw new ArgumentException ("Hexadecimal value is invalid");
ImageTypes.Add(uniqueHeaderAsHex, imageType);
}
private static Dictionary<string, string> ImageTypes;
public static bool IsImage(this Stream stream)
{
string imageType;
return stream.IsImage(out imageType);
}
public static bool IsImage(this Stream stream, out string imageType)
{
stream.Seek(0, SeekOrigin.Begin);
StringBuilder builder = new StringBuilder();
int largestByteHeader = ImageTypes.Max(img => img.Value.Length);
for (int i = 0; i < largestByteHeader; i++)
{
string bit = stream.ReadByte().ToString("X2");
builder.Append(bit);
string builtHex = builder.ToString();
bool isImage = ImageTypes.Keys.Any(img => img == builtHex);
if (isImage)
{
imageType = ImageTypes[builder.ToString()];
return true;
}
}
imageType = null;
return false;
}
}
Mi código simple
public static List<string> GetAllPhotosExtensions()
{
var list = new List<string>();
list.Add(".jpg");
list.Add(".png");
list.Add(".bmp");
list.Add(".gif");
list.Add(".jpeg");
list.Add(".tiff");
return list;
}
Compruebe si el archivo de imagen
public static bool IsPhoto(string fileName)
{
var list = FileListExtensions.GetAllPhotosExtensions();
var filename= fileName.ToLower();
bool isThere = false;
foreach(var item in list)
{
if (filename.EndsWith(item))
{
isThere = true;
break;
}
}
return isThere;
}
No es exactamente la respuesta que necesitas. Pero si es Internet, entonces tipo MIME .
No estoy seguro de cuál sería el inconveniente de rendimiento para esta solución, pero ¿no podría realizar alguna función de imagen en el archivo en un bloque de prueba que fallaría y caería en un bloque catch si no es una imagen?
Esta estrategia puede no ser la mejor en todas las situaciones, pero en el caso de que esté trabajando con ella tiene una gran ventaja: puede usar cualquier función que planee usar para procesar la imagen (si es una imagen) para el función de prueba. De esta forma, puede probar todos los tipos de imágenes actuales, pero también se extenderá a los tipos de imágenes futuros sin agregar esa nueva extensión de imagen a su lista de tipos de imágenes admitidas.
¿Alguien ve inconvenientes en esta estrategia?
Podemos usar las clases de Imagen y gráficos desde el espacio de nombres System.Drawing; para hacer nuestro trabajo Si el código funciona sin error, es una imagen, de lo contrario no lo es. Eso es dejar que el marco DotNet haga el trabajo por nosotros. El código -
public string CheckFile(file)
{
string result="";
try
{
System.Drawing.Image imgInput = System.Drawing.Image.FromFile(file);
System.Drawing.Graphics gInput = System.Drawing.Graphics.fromimage(imgInput);
Imaging.ImageFormat thisFormat = imgInput.RawFormat;
result="It is image";
}
catch(Exception ex)
{
result="It is not image";
}
return result;
}
Si desea una forma rápida de validar un archivo de imagen antes de leerlo por completo, además de comparar la extensión del archivo, puede verificar su encabezado buscando la firma del archivo (el siguiente código IsValidImageFile()
busca BMP, GIF87a, GIF89a , PNG, TIFF, JPEG )
/// <summary>
/// Reads the header of different image formats
/// </summary>
/// <param name="file">Image file</param>
/// <returns>true if valid file signature (magic number/header marker) is found</returns>
private bool IsValidImageFile(string file)
{
byte[] buffer = new byte[8];
byte[] bufferEnd = new byte[2];
var bmp = new byte[] { 0x42, 0x4D }; // BMP "BM"
var gif87a = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }; // "GIF87a"
var gif89a = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }; // "GIF89a"
var png = new byte[] { 0x89, 0x50, 0x4e, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; // PNG "/x89PNG/x0D/0xA/0x1A/0x0A"
var tiffI = new byte[] { 0x49, 0x49, 0x2A, 0x00 }; // TIFF II "II/x2A/x00"
var tiffM = new byte[] { 0x4D, 0x4D, 0x00, 0x2A }; // TIFF MM "MM/x00/x2A"
var jpeg = new byte[] { 0xFF, 0xD8, 0xFF }; // JPEG JFIF (SOI "/xFF/xD8" and half next marker xFF)
var jpegEnd = new byte[] { 0xFF, 0xD9 }; // JPEG EOI "/xFF/xD9"
try
{
using (System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
if (fs.Length > buffer.Length)
{
fs.Read(buffer, 0, buffer.Length);
fs.Position = (int)fs.Length - bufferEnd.Length;
fs.Read(bufferEnd, 0, bufferEnd.Length);
}
fs.Close();
}
if (this.ByteArrayStartsWith(buffer, bmp) ||
this.ByteArrayStartsWith(buffer, gif87a) ||
this.ByteArrayStartsWith(buffer, gif89a) ||
this.ByteArrayStartsWith(buffer, png) ||
this.ByteArrayStartsWith(buffer, tiffI) ||
this.ByteArrayStartsWith(buffer, tiffM))
{
return true;
}
if (this.ByteArrayStartsWith(buffer, jpeg))
{
// Offset 0 (Two Bytes): JPEG SOI marker (FFD8 hex)
// Offest 1 (Two Bytes): Application segment (FF?? normally ??=E0)
// Trailer (Last Two Bytes): EOI marker FFD9 hex
if (this.ByteArrayStartsWith(bufferEnd, jpegEnd))
{
return true;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Lang.Lang.ErrorTitle + " IsValidImageFile()", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return false;
}
/// <summary>
/// Returns a value indicating whether a specified subarray occurs within array
/// </summary>
/// <param name="a">Main array</param>
/// <param name="b">Subarray to seek within main array</param>
/// <returns>true if a array starts with b subarray or if b is empty; otherwise false</returns>
private bool ByteArrayStartsWith(byte[] a, byte[] b)
{
if (a.Length < b.Length)
{
return false;
}
for (int i = 0; i < b.Length; i++)
{
if (a[i] != b[i])
{
return false;
}
}
return true;
}
Comprobar la firma del encabezado puede ser rápido, ya que no carga todo el archivo ni crea objetos grandes, especialmente al procesar varios archivos. Pero no verifica si el resto de los datos está bien formado. Para hacerlo, se puede hacer un segundo paso para intentar cargar el archivo en un objeto de Image
(y de esta manera asegurarse de que el programa pueda mostrar y manejar el archivo).
bool IsValidImage(string filename)
{
try
{
using(Image newImage = Image.FromFile(filename))
{}
}
catch (OutOfMemoryException ex)
{
//The file does not have a valid image format.
//-or- GDI+ does not support the pixel format of the file
return false;
}
return true;
}
Vea si this ayuda.
EDITAR: También, Image.FromFile (....). RawFormat podría ayudar. Podría lanzar una excepción si el archivo no es una imagen.
Verifique el archivo de un encabezado conocido . (Información del enlace también se menciona en esta respuesta )
Los primeros ocho bytes de un archivo PNG siempre contienen los siguientes valores (decimales): 137 80 78 71 13 10 26 10
Yo uso el siguiente método. Utiliza el descodificador de imágenes incorporado para recuperar una lista de extensiones que el sistema reconoce como archivos de imagen, luego compara esas extensiones con la extensión del nombre de archivo que usted ingresa. Devuelve un VERDADERO / FALSO simple.
public static bool IsRecognisedImageFile(string fileName)
{
string targetExtension = System.IO.Path.GetExtension(fileName);
if (String.IsNullOrEmpty(targetExtension))
return false;
else
targetExtension = "*" + targetExtension.ToLowerInvariant();
List<string> recognisedImageExtensions = new List<string>();
foreach (System.Drawing.Imaging.ImageCodecInfo imageCodec in System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders())
recognisedImageExtensions.AddRange(imageCodec.FilenameExtension.ToLowerInvariant().Split(";".ToCharArray()));
foreach (string extension in recognisedImageExtensions)
{
if (extension.Equals(targetExtension))
{
return true;
}
}
return false;
}
System.Web.MimeMapping.GetMimeMapping(filename).StartsWith("image/");
MimeMapping.GetMimeMapping
produce estos resultados:
- archivo.jpg: imagen / jpeg
- file.gif: image / gif
- file.jpeg: image / jpeg
- file.png: image / png
- file.bmp: image / bmp
- archivo.tiff: imagen / tiff
- file.svg: application / octet-stream
El archivo .svg que no devuelve una imagen / tipo MIME funciona en la mayoría de los casos porque probablemente no va a procesar una imagen vectorial como lo haría con una imagen escalar. Al verificar el tipo MIME, tenga en cuenta que SVG tiene el tipo MIME estándar de imagen / svg + xml, incluso si GetMimeMapping
no lo devuelve.