Znajdź format obrazu przy użyciu obiektu Bitmap w C #

84

Ładuję binarne bajty dysku twardego z plikiem obrazu i ładuję go do obiektu Bitmap. Jak znaleźć typ obrazu [JPEG, PNG, BMP itp.] W obiekcie Bitmap?

Wygląda banalnie. Ale nie mogłem tego rozgryźć!

Czy istnieje alternatywne podejście?

Doceń twoją odpowiedź.

AKTUALIZACJA PRAWIDŁOWE ROZWIĄZANIE:

@CMS: Dzięki za poprawną odpowiedź!

Przykładowy kod, aby to osiągnąć.

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;
    }
}
ołówek
źródło
3
Możesz dodać System.Drawing.Imagingprzestrzeń nazw do dyrektyw using, aby sprawdzanie formatu było mniej szczegółowe ...
Christian C. Salvadó
@CMS: Zgoda! Chciałem wyświetlić pełną przestrzeń nazw, aby uzyskać dodatkowe informacje.
ołówek spóźniony
2
Hmmm ... Próbowałem tej samej techniki, ale to nie działa. Mam załadowany plik PNG i kiedy porównuję jego wartość RawFormat ze wszystkimi instancjami ImageFormat. *, Żaden z nich nie pasuje. Rzeczywista wartość RawFormat to {b96b3caf-0728-11d3-9d7b-0000f81ef32e}.
Igor Brejc

Odpowiedzi:

106

Jeśli chcesz poznać format obrazu, możesz załadować plik z klasą Image i sprawdzić jego właściwość RawFormat :

using(Image img = Image.FromFile(@"C:\path\to\img.jpg"))
{
    if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
    {
      // ...
    }
}
Christian C. Salvadó
źródło
29
Uwaga: wygląda na to, że img.RawFormat == ImageFormat.Jpegnie działa. Państwo mają w użyciu img.RawFormat.Equals(ImageFormat.Jpeg).
BlueRaja - Danny Pflughoeft
1
@BlueRaja, Yeah, dlaczego tak jest? Czy większość klas .NET nie przesłania zarówno metody Equals (), jak i operatora? A może źle to sformułowałem - czy .NET nie używa metody .Equals () domyślnie, gdy używam operatora ==? Czy się mylę?
Pandincus
Gah! Nic dziwnego, że to nie działało. Założyłem, że == załatwił sprawę. Cholera! Dzięki chłopaki, zaoszczędziłem mi teraz trochę czasu.
Wszechobecny Che
1
O ile nie zostanie zastąpiony lub jeden z kilku wbudowanych typów, nie ==używa równości odwołań Equals. Oprócz używania Equalssiebie, możesz użyć statycznego object.Equals(obj1, obj2)(który wywołuje Equals) dla prostego bezpieczeństwa zerowego.
Tim S.,
59

Oto moja metoda rozszerzenia. Mam nadzieję, że to komuś pomoże.

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;            
    }
sebacipo
źródło
10
Nie mogę uwierzyć, że framework .NET nie ma tego upieczonego i że jest to jedyny sposób. Właściwie jestem w szoku.
simonlchilds
18

oto mój kod do tego. Najpierw musisz załadować cały obraz lub nagłówek (pierwsze 4 bajty) do tablicy bajtów.

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
źródło
1
JPEG należy sprawdzić pod kątem {255, 216, 255}. Tutaj jest info en.wikipedia.org/wiki/JPEG
Mirodil
9

oczywiście, że możesz. ImageFormatniewiele znaczy.ImageCodecInfoma znacznie większe znaczenie.

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>

kod:

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

wyjście debugowania:

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
źródło
Dobrze znajdź Alex! Choć wygląda to niechlujnie, ale zobacz, jak podstawy przekształciły się w kilka czystych metod rozszerzenia poniżej.
Nicholas Petersen
2

Po prostu nie możesz. Powodem jest to, że Bitmapa jest typem obrazu w taki sam sposób, jak JPEG, PNG itp. Po załadowaniu obrazu do mapy bitowej obraz w formacie mapy bitowej. Nie ma sposobu, aby spojrzeć na bitmapę i zrozumieć oryginalne kodowanie obrazu (jeśli jest nawet inne niż Bitmap).

JaredPar
źródło
1
Myślę, że w tym przypadku Bitmap (myląco) to nazwa klasy w C #. Klasa Bitmap zawiera obraz, który prawdopodobnie może zawierać pliki jpg, giff, bmp itp. W każdym innym przypadku tak, masz całkowitą rację.
DarcyThomas
2

Aby nie zawracać sobie głowy starym tematem, ale aby zakończyć tę dyskusję, chcę podzielić się moim sposobem przeszukiwania wszystkich formatów obrazów znanych w systemie 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;
    }
}

Teraz możesz użyć go jako rozszerzenia obrazu, jak pokazano poniżej:

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);
}
Agent CK
źródło
1

Opierając się na powyższej pracy Alexa (którą faktycznie głosuję jako rozwiązanie, ponieważ jest to jedna linia - ale nie mogę jeszcze głosować haha), wymyśliłem następującą funkcję dla biblioteki obrazów. Wymaga 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
źródło
0

Kilka czystych metod rozszerzania typu w Imagecelu określenia tego, na podstawie znalezienia Alexa powyżej ( ImageCodecInfo.GetImageDecoders()).

Jest to wysoce zoptymalizowane po pierwszym wywołaniu, ponieważ statyczny ImageCodecsDictionary jest zapisywany w pamięci (ale tylko wtedy, gdy został użyty raz).

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

}
Nicholas Petersen
źródło
0

jeden dziwny problem, z którym miałem do czynienia, gdy próbowałem uzyskać typ MIME za pomocą imagecodeinfo .. dla niektórych plików png guidy nie były dokładnie takie same ...

najpierw sprawdzałem za pomocą ImageCodecinfo i jeśli kod nie znalazł formatu obrazu, porównałem format obrazu przy użyciu rozwiązania Matthiasa Wuttke.

jeśli oba powyższe rozwiązania zawiodły, użyj metody rozszerzenia, aby uzyskać typ MIME pliku.

jeśli typ MIME zmienia się, plik również się zmienia, obliczaliśmy sumę kontrolną pobranych plików, aby dopasować ją do sumy kontrolnej oryginalnego pliku na serwerze ... więc dla nas ważne było, aby uzyskać odpowiedni plik jako wynik.

Samuel Joy
źródło
0

Agencie CK , podobała mi się twoja metoda rozszerzenia i dodałem przeciążenie ciągów, a ponadto zmniejszyłem kod dla twojej metody:

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
źródło
0

Najprostszą metodę zaproponował Cesare Imperiali :

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

Jednak .ToString () dla .jpg zwraca „[ImageFormat: b96b3cae-0728-11d3-9d7b-0000f81ef32e]” zamiast „Jpeg”. Jeśli to dla Ciebie ważne, oto moje rozwiązanie:

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
źródło