ฉันกำลังวนซ้ำไดเร็กทอรีและคัดลอกไฟล์ทั้งหมด ตอนนี้ฉันกำลังตรวจสอบ string.EndsWith
สำหรับ ".jpg"
หรือ ".png"
ฯลฯ .
มีวิธีการใดที่ดีกว่าในการพิจารณาว่าไฟล์เป็นรูปภาพ (รูปภาพประเภทใด ๆ ) โดยไม่ต้องตรวจสอบแฮ็กเหมือนด้านบนหรือไม่
ฉันกำลังวนซ้ำไดเร็กทอรีและคัดลอกไฟล์ทั้งหมด ตอนนี้ฉันกำลังตรวจสอบ string.EndsWith
สำหรับ ".jpg"
หรือ ".png"
ฯลฯ .
มีวิธีการใดที่ดีกว่าในการพิจารณาว่าไฟล์เป็นรูปภาพ (รูปภาพประเภทใด ๆ ) โดยไม่ต้องตรวจสอบแฮ็กเหมือนด้านบนหรือไม่
ตรวจสอบไฟล์เพื่อหาส่วนหัวที่รู้จัก . (ข้อมูลจากลิงก์ที่กล่าวถึงในคำตอบนี้)
แปดไบต์แรกของไฟล์ PNG จะมีค่า (ทศนิยม) ต่อไปนี้เสมอ: 137 80 78 71 13 10 26 10
ลองดู System.IO.Path.GetExtension
นี่คือตัวอย่างสั้นๆ
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
}
}
}
System.Web.MimeMapping.GetMimeMapping(filename).StartsWith("image/");
MimeMapping.GetMimeMapping
ให้ผลลัพธ์เหล่านี้:
file.svg ไม่ส่งคืนรูปภาพ/ ประเภท MIME ในกรณีส่วนใหญ่เพราะคุณอาจไม่ประมวลผลภาพเวกเตอร์เหมือนที่คุณทำกับภาพสเกลาร์ เมื่อตรวจสอบประเภท MIME โปรดทราบว่า SVG มีประเภท MIME มาตรฐานของ image/svg+xml แม้ว่า GetMimeMapping
จะไม่ส่งคืนก็ตาม
วิธีนี้จะดูสองสามไบต์แรกของไฟล์และพิจารณาว่าเป็นรูปภาพหรือไม่
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;
}
}
ฉันได้ทำการเปลี่ยนแปลงเล็กน้อยกับที่กล่าวมาข้างต้นเพื่อให้คุณสามารถเพิ่มรูปภาพของคุณเองได้หากต้องการ รวมถึงลบคอลเลกชันที่ไม่จำเป็นต้องเริ่มต้นด้วยออกไปด้วย ฉันยังเพิ่มการโอเวอร์โหลดที่ยอมรับพารามิเตอร์ out
ประเภท string
โดยตั้งค่าเป็นประเภทของภาพที่สตรีมประกอบด้วย
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;
}
}
int largestByteHeader = ImageTypes.Max(img => img.Value.Length);
- ความยาวควรหารด้วย 2 เนื่องจากอักขระแต่ละตัวในสตริงเลขฐานสิบหกมีค่าเพียง 4 บิต ไม่ใช่ 8 และคุณใช้ผลลัพธ์ของคำสั่งนี้ราวกับว่าเป็นจำนวนไบต์ใน ส่วนหัว ตัวอย่างเช่น PNG ส่วนหัวคือ 8 ไบต์ แต่โค้ดของคุณคำนวณผิดพลาดเป็น 16 ไบต์ มันยังคงใช้งานได้เพราะมันแค่สแกนในปริมาณที่นานกว่าที่จำเป็นในกรณีที่ไม่ใช่รูปภาพ แต่มันทำให้โค้ดสับสน
- person chillNZ; 06.08.2018
img.Value.Length
ควรเป็น img.Key.Length
(คุณพูดถูกในวิธีการขยายโดยไม่จำเป็นต้องเปลี่ยน)
- person chillNZ; 06.08.2018
เราสามารถใช้คลาสรูปภาพและกราฟิกจากเนมสเปซ System. Drawing; เพื่อทำงานของเรา หากโค้ดทำงานได้โดยไม่มีข้อผิดพลาด แสดงว่าเป็นรูปภาพ อย่างอื่นไม่ใช่ นั่นคือปล่อยให้ DotNet Framework ทำงานแทนเรา รหัส -
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;
}
imgInput.Dispose(); gInput.Dispose();
เว้นแต่ตัวจัดการไฟล์จะเปิดอยู่และกระบวนการอื่นไม่สามารถใช้งานได้
- person Beginner; 03.08.2017
หากคุณต้องการวิธีที่รวดเร็วในการตรวจสอบความถูกต้องของไฟล์รูปภาพก่อนที่จะอ่านแบบเต็มจากไฟล์ นอกจากการเปรียบเทียบนามสกุลไฟล์แล้ว คุณสามารถตรวจสอบส่วนหัวของไฟล์เพื่อค้นหาลายเซ็นไฟล์ได้ (โค้ดต่อไปนี้ IsValidImageFile()
จะตรวจสอบ 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;
}
การตรวจสอบลายเซ็นส่วนหัวสามารถทำได้อย่างรวดเร็ว เนื่องจากไม่ได้โหลดทั้งไฟล์หรือสร้างอ็อบเจ็กต์ขนาดใหญ่ โดยเฉพาะอย่างยิ่งเมื่อประมวลผลหลายไฟล์ แต่ไม่ได้ตรวจสอบว่าข้อมูลส่วนที่เหลือมีรูปแบบที่ดีหรือไม่ ในการทำเช่นนั้น ขั้นตอนที่สองในการพยายามโหลดไฟล์ไปยังออบเจ็กต์ Image
สามารถทำได้ (และวิธีนี้ทำให้แน่ใจได้ว่าไฟล์สามารถแสดงและจัดการโดยโปรแกรมของคุณ)
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;
}
ฉันใช้วิธีการต่อไปนี้ โดยจะใช้ตัวถอดรหัสรูปภาพในตัวเพื่อดึงรายการส่วนขยายที่ระบบรับรู้ว่าเป็นไฟล์รูปภาพ จากนั้นเปรียบเทียบส่วนขยายเหล่านั้นกับนามสกุลของชื่อไฟล์ที่คุณส่งมา ส่งกลับค่า TRUE/FALSE แบบธรรมดา
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;
}
ดูว่า สิ่งนี้ ช่วยได้หรือไม่
แก้ไข: นอกจากนี้ Image.FromFile(....).RawFormat อาจช่วยได้ อาจทำให้เกิดข้อยกเว้นหากไฟล์ไม่ใช่รูปภาพ
ไม่ใช่คำตอบที่คุณต้องการอย่างแน่นอน แต่ถ้าเป็นอินเทอร์เน็ต ให้พิมพ์ MIME
ฉันไม่แน่ใจว่าข้อเสียเปรียบด้านประสิทธิภาพจะเป็นเช่นไรสำหรับโซลูชันนี้ แต่คุณไม่สามารถใช้งานฟังก์ชันรูปภาพบางอย่างกับไฟล์ในบล็อก try ที่จะล้มเหลวและตกไปที่บล็อกที่รับได้หากไม่ใช่รูปภาพ
กลยุทธ์นี้อาจไม่ใช่ทางออกที่ดีที่สุดในทุกสถานการณ์ แต่ในกรณีที่ฉันกำลังดำเนินการอยู่ก็มีข้อได้เปรียบที่สำคัญอย่างหนึ่ง: คุณสามารถใช้ฟังก์ชันใดก็ได้ที่คุณวางแผนจะใช้ในการประมวลผลรูปภาพ (หากเป็นรูปภาพ) สำหรับ ฟังก์ชั่นทดสอบ ด้วยวิธีนี้ คุณสามารถทดสอบประเภทรูปภาพปัจจุบันทั้งหมดได้ แต่จะขยายไปยังประเภทรูปภาพในอนาคตด้วย โดยไม่ต้องเพิ่มส่วนขยายรูปภาพใหม่นั้นลงในรายการประเภทรูปภาพที่รองรับ
ไม่มีใครเห็นข้อเสียของกลยุทธ์นี้หรือไม่?
นี่คือสิ่งที่ฉันใช้ - มันเป็นเพียงการปรับแต่งคำตอบของ @dylmcc เพื่อให้อ่านง่ายขึ้นอีกเล็กน้อย
public static bool IsRecognisedImageFile(string fileName)
{
string targetExtension = System.IO.Path.GetExtension(fileName);
if (String.IsNullOrEmpty(targetExtension))
{
return false;
}
var recognisedImageExtensions = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders().SelectMany(codec => codec.FilenameExtension.ToLowerInvariant().Split(';'));
targetExtension = "*" + targetExtension.ToLowerInvariant();
return recognisedImageExtensions.Contains(targetExtension);
}
นี่เป็นเรื่องยุ่งยาก หากไฟล์ไม่ใช่รูปภาพ ข้อยกเว้นจะเกิดขึ้น จากนั้นเราก็สามารถตรวจสอบได้ว่าไฟล์นั้นเป็นรูปภาพหรือไม่
using (Stream stream = File.OpenRead(file))
{
try
{
using (Image sourceImage = Image.FromStream(stream, false, false))
{
}
}
catch (Exception x)
{
if (x.Message.Contains("not valid"))
{
Console.Write("This is not a Image.");
}
}
}
รหัสง่ายๆของฉัน
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;
}
ตรวจสอบว่าไฟล์รูปภาพ
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;
}