Найти формат изображения с помощью объекта Bitmap в C #

84

Я загружаю двоичные байты жесткого диска с файлом изображения и загружаю его в объект Bitmap. Как мне найти тип изображения [JPEG, PNG, BMP и т. Д.] Из объекта Bitmap?

Выглядит банально. Но не мог понять!

Есть ли альтернативный подход?

Оцените ваш ответ.

ОБНОВЛЕННОЕ ПРАВИЛЬНОЕ РЕШЕНИЕ:

@CMS: Спасибо за правильный ответ!

Пример кода для этого.

using (MemoryStream imageMemStream = new MemoryStream(fileData))
{
    using (Bitmap bitmap = new Bitmap(imageMemStream))
    {
        ImageFormat imageFormat = bitmap.RawFormat;
        if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
            //It's a JPEG;
        else if (bitmap.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Png))
            //It's a PNG;
    }
}
грифель
источник
3
Вы можете добавить System.Drawing.Imagingпространство имен к своим директивам using, чтобы сделать проверки формата менее подробными ...
Кристиан С. Сальвадо,
@CMS: Согласен! Требуется отобразить полное пространство имен для получения дополнительной информации.
Pencilslate
2
Хммм ... Я пробовал ту же технику, но она не работает. У меня загружен PNG, и когда я сравниваю его значение RawFormat со всеми экземплярами ImageFormat. *, Ни один из них не соответствует. Фактическое значение RawFormat - {b96b3caf-0728-11d3-9d7b-0000f81ef32e}.
Игорь Брейц

Ответы:

106

Если вы хотите узнать формат изображения, вы можете загрузить файл с помощью класса Image и проверить его свойство RawFormat :

using(Image img = Image.FromFile(@"C:\path\to\img.jpg"))
{
    if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
    {
      // ...
    }
}
Кристиан К. Сальвадо
источник
29
Примечание: похоже, что img.RawFormat == ImageFormat.Jpegэто не работает. Вы должны использовать img.RawFormat.Equals(ImageFormat.Jpeg).
BlueRaja - Дэнни Пфлугофт
1
@BlueRaja, ага, а это почему? Разве большинство классов .NET не переопределяют и метод Equals (), и оператор? Или, может быть, я неправильно сформулировал - разве .NET не использует метод .Equals () по умолчанию при использовании оператора ==? Я не прав?
Pandincus
Ага! Не удивительно , что не работает. Я предположил, что == помогло. Черт! Спасибо, ребята, только что сэкономили мне кучу времени.
Вездесущий Че
1
Если он не переопределен или не используется один из нескольких встроенных типов, ==ссылочное равенство не используется Equals. Помимо использования Equalsсебя, вы можете использовать static object.Equals(obj1, obj2)(который вызывает Equals) для простой нулевой безопасности.
Тим С.
59

Вот мой метод расширения. Надеюсь, это кому-то поможет.

public static System.Drawing.Imaging.ImageFormat GetImageFormat(this System.Drawing.Image img)
    {             
        if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
            return System.Drawing.Imaging.ImageFormat.Jpeg;
        if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Bmp))
            return System.Drawing.Imaging.ImageFormat.Bmp;
        if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Png))
            return System.Drawing.Imaging.ImageFormat.Png;
        if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Emf))
            return System.Drawing.Imaging.ImageFormat.Emf;
        if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Exif))
            return System.Drawing.Imaging.ImageFormat.Exif;
        if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Gif))
            return System.Drawing.Imaging.ImageFormat.Gif;
        if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Icon))
            return System.Drawing.Imaging.ImageFormat.Icon;
        if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.MemoryBmp))
            return System.Drawing.Imaging.ImageFormat.MemoryBmp;
        if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Tiff))
            return System.Drawing.Imaging.ImageFormat.Tiff;
        else
            return System.Drawing.Imaging.ImageFormat.Wmf;            
    }
себаципо
источник
10
Я не могу поверить, что в .NET framework этого нет и что это единственный способ. Я вообще в шоке.
simonlchilds 01
18

вот мой код для этого. Вы должны сначала загрузить полное изображение или заголовок (первые 4 байта) в массив байтов.

public enum ImageFormat
{
    Bmp,
    Jpeg,
    Gif,
    Tiff,
    Png,
    Unknown
}

public static ImageFormat GetImageFormat(byte[] bytes)
{
    // see http://www.mikekunz.com/image_file_header.html  
    var bmp    = Encoding.ASCII.GetBytes("BM");     // BMP
    var gif    = Encoding.ASCII.GetBytes("GIF");    // GIF
    var png    = new byte[] { 137, 80, 78, 71 };    // PNG
    var tiff   = new byte[] { 73, 73, 42 };         // TIFF
    var tiff2  = new byte[] { 77, 77, 42 };         // TIFF
    var jpeg   = new byte[] { 255, 216, 255, 224 }; // jpeg
    var jpeg2  = new byte[] { 255, 216, 255, 225 }; // jpeg canon

    if (bmp.SequenceEqual(bytes.Take(bmp.Length)))
        return ImageFormat.Bmp;

    if (gif.SequenceEqual(bytes.Take(gif.Length)))
        return ImageFormat.Gif;

    if (png.SequenceEqual(bytes.Take(png.Length)))
        return ImageFormat.Png;

    if (tiff.SequenceEqual(bytes.Take(tiff.Length)))
        return ImageFormat.Tiff;

    if (tiff2.SequenceEqual(bytes.Take(tiff2.Length)))
        return ImageFormat.Tiff;

    if (jpeg.SequenceEqual(bytes.Take(jpeg.Length)))
        return ImageFormat.Jpeg;

    if (jpeg2.SequenceEqual(bytes.Take(jpeg2.Length)))
        return ImageFormat.Jpeg;

    return ImageFormat.Unknown;
}
Alex
источник
1
JPEG необходимо проверить на {255, 216, 255}. Вот информация en.wikipedia.org/wiki/JPEG
Миродил 02
9

конечно вы можете. ImageFormatмало значит. ImageCodecInfoимеет гораздо большее значение.

red_dot.png

red_dot.png

<a href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==">
    <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="red_dot.png" title="red_dot.png"/>
</a>

код:

using System.Linq;

//...

//get image
var file_bytes = System.Convert.FromBase64String(@"iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==");
var file_stream = new System.IO.MemoryStream(file_bytes);
var file_image = System.Drawing.Image.FromStream(file_stream);

//list image formats
var image_formats = typeof(System.Drawing.Imaging.ImageFormat).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static).ToList().ConvertAll(property => property.GetValue(null, null));
System.Diagnostics.Debug.WriteLine(image_formats.Count, "image_formats");
foreach(var image_format in image_formats) {
    System.Diagnostics.Debug.WriteLine(image_format, "image_formats");
}

//get image format
var file_image_format = typeof(System.Drawing.Imaging.ImageFormat).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static).ToList().ConvertAll(property => property.GetValue(null, null)).Single(image_format => image_format.Equals(file_image.RawFormat));
System.Diagnostics.Debug.WriteLine(file_image_format, "file_image_format");

//list image codecs
var image_codecs = System.Drawing.Imaging.ImageCodecInfo.GetImageDecoders().ToList();
System.Diagnostics.Debug.WriteLine(image_codecs.Count, "image_codecs");
foreach(var image_codec in image_codecs) {
    System.Diagnostics.Debug.WriteLine(image_codec.CodecName + ", mime: " + image_codec.MimeType + ", extension: " + @image_codec.FilenameExtension, "image_codecs");
}

//get image codec
var file_image_format_codec = System.Drawing.Imaging.ImageCodecInfo.GetImageDecoders().ToList().Single(image_codec => image_codec.FormatID == file_image.RawFormat.Guid);
System.Diagnostics.Debug.WriteLine(file_image_format_codec.CodecName + ", mime: " + file_image_format_codec.MimeType + ", extension: " + file_image_format_codec.FilenameExtension, "image_codecs", "file_image_format_type");

вывод отладки:

image_formats: 10
image_formats: MemoryBMP
image_formats: Bmp
image_formats: Emf
image_formats: Wmf
image_formats: Gif
image_formats: Jpeg
image_formats: Png
image_formats: Tiff
image_formats: Exif
image_formats: Icon
file_image_format: Png
image_codecs: 8
image_codecs: Built-in BMP Codec, mime: image/bmp, extension: *.BMP;*.DIB;*.RLE
image_codecs: Built-in JPEG Codec, mime: image/jpeg, extension: *.JPG;*.JPEG;*.JPE;*.JFIF
image_codecs: Built-in GIF Codec, mime: image/gif, extension: *.GIF
image_codecs: Built-in EMF Codec, mime: image/x-emf, extension: *.EMF
image_codecs: Built-in WMF Codec, mime: image/x-wmf, extension: *.WMF
image_codecs: Built-in TIFF Codec, mime: image/tiff, extension: *.TIF;*.TIFF
image_codecs: Built-in PNG Codec, mime: image/png, extension: *.PNG
image_codecs: Built-in ICO Codec, mime: image/x-icon, extension: *.ICO
Built-in PNG Codec, mime: image/png, extension: *.PNG
Alex
источник
Хорошая находка, Алекс! Хотя это выглядит запутанным, но посмотрите, как основы превратились в пару чистых методов расширения ниже.
Николас Петерсен
2

Проще говоря, вы не можете. Причина в том, что Bitmap - это такой же тип изображения, как и JPEG, PNG и т. Д. После того, как вы загрузите изображение в Bitmap, вы получите изображение в формате bitmap. Невозможно взглянуть на растровое изображение и понять исходную кодировку изображения (даже если она отличается от Bitmap).

ДжаредПар
источник
1
Я думаю, что в этом случае Bitmap (сбивает с толку) - это имя класса в C #. Класс Bitmap содержит изображение, которое предположительно может быть jpg, giff, bmp и т. Д. В любых других обстоятельствах да, вы абсолютно правы.
DarcyThomas
2

Чтобы не беспокоиться о старой теме, но чтобы завершить это обсуждение, я хочу поделиться своим способом запроса всех форматов изображений, известных Windows.

using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;

public static class ImageExtentions
{
    public static ImageCodecInfo GetCodecInfo(this System.Drawing.Image img)
    {
        ImageCodecInfo[] decoders = ImageCodecInfo.GetImageDecoders();
        foreach (ImageCodecInfo decoder in decoders)
            if (img.RawFormat.Guid == decoder.FormatID)
                return decoder;
        return null;
    }
}

Теперь вы можете использовать его как расширение изображения, как показано ниже:

public void Test(Image img)
{
    ImageCodecInfo info = img.GetCodecInfo();
    if (info == null)
        Trace.TraceError("Image format is unkown");
    else
        Trace.TraceInformation("Image format is " + info.FormatDescription);
}
Агент СК
источник
1

Основываясь на работе Алекса выше (которую я фактически голосую как решение, поскольку это одна строка, но я еще не могу проголосовать, ха-ха), я придумал следующую функцию для библиотеки изображений. Требуется 4.0

  Public Enum Formats
    Unknown
    Bmp
    Emf
    Wmf
    Gif
    Jpeg
    Png
    Tiff
    Icon
  End Enum

  Public Shared Function ImageFormat(ByVal Image As System.Drawing.Image) As Formats
    If Not System.Enum.TryParse(Of Formats)(System.Drawing.Imaging.ImageCodecInfo.GetImageDecoders().ToList().[Single](Function(ImageCodecInfo) ImageCodecInfo.FormatID = Image.RawFormat.Guid).FormatDescription, True, ImageFormat) Then
      Return Formats.Unknown
    End If
  End Function
toddmo
источник
0

Пара чистых методов расширения по типу Imageдля определения этого, основанных на находке Алекса выше ( ImageCodecInfo.GetImageDecoders()).

Это сильно оптимизировано после первого вызова, поскольку статический ImageCodecsDictionary сохраняется в памяти (но только после того, как он был использован один раз).

public static class ImageCodecInfoX
{

    private static Dictionary<Guid, ImageCodecInfoFull> _imageCodecsDictionary;

    public static Dictionary<Guid, ImageCodecInfoFull> ImageCodecsDictionary 
    {
        get
        {
            if (_imageCodecsDictionary == null) {
                _imageCodecsDictionary =
                    ImageCodecInfo.GetImageDecoders()
                    .Select(i => {
                        var format = ImageFormats.Unknown;
                        switch (i.FormatDescription.ToLower()) {
                            case "jpeg": format = ImageFormats.Jpeg; break;
                            case "png": format = ImageFormats.Png; break;
                            case "icon": format = ImageFormats.Icon; break;
                            case "gif": format = ImageFormats.Gif; break;
                            case "bmp": format = ImageFormats.Bmp; break;
                            case "tiff": format = ImageFormats.Tiff; break;
                            case "emf": format = ImageFormats.Emf; break;
                            case "wmf": format = ImageFormats.Wmf; break;
                        }
                        return new ImageCodecInfoFull(i) { Format = format };
                    })
                    .ToDictionary(c => c.CodecInfo.FormatID);
            }
            return _imageCodecsDictionary;
        }
    }

    public static ImageCodecInfoFull CodecInfo(this Image image)
    {
        ImageCodecInfoFull codecInfo = null;

        if (!ImageCodecsDictionary.TryGetValue(image.RawFormat.Guid, out codecInfo))
            return null;
        return codecInfo;
    }

    public static ImageFormats Format(this Image image)
    {
        var codec = image.CodecInfo();
        return codec == null ? ImageFormats.Unknown : codec.Format;
    }
}

public enum ImageFormats { Jpeg, Png, Icon, Gif, Bmp, Emf, Wmf, Tiff, Unknown }

/// <summary>
/// Couples ImageCodecInfo with an ImageFormats type.
/// </summary>
public class ImageCodecInfoFull
{
    public ImageCodecInfoFull(ImageCodecInfo codecInfo = null)
    {
        Format = ImageFormats.Unknown;
        CodecInfo = codecInfo;
    }

    public ImageCodecInfo CodecInfo { get; set; }

    public ImageFormats Format { get; set; }

}
Николас Петерсен
источник
0

одна странная проблема, с которой я столкнулся, когда пытался получить тип mime с помощью imagecodeinfo ... для некоторых файлов png направляющие были не совсем такими же ...

сначала я проверял с помощью ImageCodecinfo, и если код не находит формат изображения, я сравнивал формат изображения, используя решение Маттиаса Вуттке.

если оба вышеупомянутых решения не сработали, тогда использовался метод расширения для получения типа файла mime ..

если тип mime изменяется, файл также изменяется, мы вычисляли контрольную сумму загруженных файлов, чтобы она соответствовала контрольной сумме исходного файла на сервере ... поэтому для нас было важно получить правильный файл в качестве вывода.

Сэмюэл Джой
источник
0

Агент СК , мне понравился ваш метод расширения, я добавил перегрузку строки, плюс я сократил код для вашего метода:

public static class ImageExtentions
{
    public static ImageCodecInfo GetCodecInfo(this Image img) =>
        ImageCodecInfo.GetImageDecoders().FirstOrDefault(decoder => decoder.FormatID == img.RawFormat.Guid);

    // Note: this will throw an exception if "file" is not an Image file
    // quick fix is a try/catch, but there are more sophisticated methods
    public static ImageCodecInfo GetCodecInfo(this string file)
    {
        using (var img = Image.FromFile(file))
            return img.GetCodecInfo();
    }
}

// Usage:
string file = @"C:\MyImage.tif";
string description = $"Image format is {file.GetCodecInfo()?.FormatDescription ?? "unknown"}.";
Console.WriteLine(description);
JohnnyIV
источник
0

Чезаре Империали предложил самый простой метод :

var format = new ImageFormat(Image.FromFile(myFile).RawFormat.Guid);

Однако .ToString () для .jpg возвращает «[ImageFormat: b96b3cae-0728-11d3-9d7b-0000f81ef32e]» вместо «Jpeg». Если это важно для вас, вот мое решение:

public static class ImageFilesHelper
{
    public static List<ImageFormat> ImageFormats =>
        typeof(ImageFormat).GetProperties(BindingFlags.Static | BindingFlags.Public)
          .Select(p => (ImageFormat)p.GetValue(null, null)).ToList();

    public static ImageFormat ImageFormatFromRawFormat(ImageFormat raw) =>
        ImageFormats.FirstOrDefault(f => raw.Equals(f)) ?? ImageFormat.Bmp;

}
// usage:
var format = ImageFilesHelper.ImageFormatFromRawFormat(Image.FromFile(myFile).RawFormat);
JohnnyIV
источник