我怎么知道从流中获得的图像格式?

时间:2011-03-06 08:38:11

标签: c# image

我从某个Web服务获取字节流。此字节流包含图像的二进制日期,我使用下面的方法将其转换为Image实例。

我需要知道我有什么样的形象。它是简单的位图(*.bmp)还是JPEG图像(*.jpg)还是png图像?

我怎样才能找到它?

    public static Image byteArrayToImage( byte[] bmpBytes )
    {
        Image image = null;
        using( MemoryStream stream = new MemoryStream( bmpBytes ) )
        {
            image = Image.FromStream( stream );
        }

        return image;
    }

6 个答案:

答案 0 :(得分:112)

您可以结帐Image.RawFormat财产。因此,一旦从流中加载图像,就可以测试:

if (ImageFormat.Jpeg.Equals(image.RawFormat))
{
    // JPEG
}
else if (ImageFormat.Png.Equals(image.RawFormat))
{
    // PNG
}
else if (ImageFormat.Gif.Equals(image.RawFormat))
{
    // GIF
}
... etc

答案 1 :(得分:18)

您可以从以下代码中获取图像类型:

//get your image from bytaArrayToImage
Image img = byteArrayToImage(new byte[] { });

//get the format/file type
string ext = new ImageFormatConverter().ConvertToString(img.RawFormat);

答案 2 :(得分:7)

在C#中,我们可以使用Image.RawFormat来检查图像的ImageFormat。但属性RawFormat似乎在紧凑框架中不可用。所以我认为你必须使用Imaging API。需要很多类型。在下面我要举一个例子,我认为它会帮助你解决一些问题。

using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;

/// <summary>
/// This structure contains parameters related to an image.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct ImageInfo
{
    #region Fields

    /// <summary>
    /// A GUID value that identifies the file format for the native image data. This value is an image format identifier. For more information, see Imaging GUIDs.
    /// </summary>
    public Guid RawDataFormat;

    public PixelFormatID PixelFormat;

    public uint Width;

    public uint Height;

    public uint TileWidth;

    public uint TileHeight;

    public double Xdpi;

    public double Ydpi;

    public SinkFlags Flags;

    #endregion
}

[StructLayout(LayoutKind.Sequential)]
public struct FILETIME
{
    #region Fields

    public int dwLowDateTime;

    public int dwHighDateTime;

    #endregion
}

[StructLayout(LayoutKind.Sequential)]
internal struct BitmapData
{
    #region Fields

    public int Width;

    public int Height;

    public int Stride;

    public PixelFormatID PixelFormat;

    public IntPtr Scan0;

    public IntPtr Reserved;

    #endregion
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STATSTG
{
    #region Fields

    [MarshalAs(UnmanagedType.LPWStr)]
    public string pwcsName;

    public int type;

    public long cbSize;

    public FILETIME mtime;

    public FILETIME ctime;

    public FILETIME atime;

    public int grfMode;

    public int grfLocksSupported;

    public Guid clsid;

    public int grfStateBits;

    public int reserved;

    #endregion
}

/// <summary>
/// COM IStream interface
/// </summary>
[ComImport]
[Guid("0000000c-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStream
{
    void Read([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbRead);

    void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbWritten);

    void Seek(long dlibMove, int origin, IntPtr plibNewPosition);

    void SetSize(long libNewSize);

    void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);

    void Commit(int grfCommitFlags);

    void Revert();

    void LockRegion(long libOffset, long cb, int lockType);

    void UnlockRegion(long libOffset, long cb, int lockType);

    void Stat(out STATSTG pstatstg, int grfStatFlag);

    void Clone(out IStream ppstm);
}

/// <summary>
/// Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK
/// </summary>
[ComImport]
[Guid("327ABDAA-072B-11D3-9D7B-0000F81EF32E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
internal interface IBitmapImage
{
    uint GetSize(out Size size);

    uint GetPixelFormatID(out PixelFormatID pixelFormat);

    uint LockBits(ref RECT rect, uint flags, PixelFormatID pixelFormat, ref BitmapData lockedBitmapData);

    uint UnlockBits(ref BitmapData lockedBitmapData);

    uint GetPalette(); // This is a place holder

    uint SetPalette(); // This is a place holder
}

/// <summary>
/// Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK
/// </summary>
[ComImport]
[Guid("327ABDA7-072B-11D3-9D7B-0000F81EF32E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
internal interface IImagingFactory
{
    uint CreateImageFromStream(IStream stream, out IImage image);

    uint CreateImageFromFile(string filename, out IImage image);

    // We need the MarshalAs attribute here to keep COM interop from sending the buffer down as a Safe Array.
    // uint CreateImageFromBuffer([MarshalAs(UnmanagedType.LPArray)] byte[] buffer, uint size, BufferDisposalFlag disposalFlag, out IImage image);
    uint CreateImageFromBuffer(IntPtr buffer, uint size, BufferDisposalFlag disposalFlag, out IImage image);

    uint CreateNewBitmap();            // This is a place holder

    uint CreateBitmapFromImage(IImage image, uint width, uint height, PixelFormatID pixelFormat, InterpolationHint hints, out IBitmapImage bitmap);      // This is a place holder

    uint CreateBitmapFromBuffer();     // This is a place holder

    uint CreateImageDecoder();         // This is a place holder

    uint CreateImageEncoderToStream(); // This is a place holder

    uint CreateImageEncoderToFile(ref Guid clsid, string filename, out IImageEncoder encoder);

    uint GetInstalledDecoders([Out] out uint size, [Out] out IntPtr decoders);

    uint GetInstalledEncoders([Out] out uint size, [Out] out IntPtr ecoders);

    uint InstallImageCodec();          // This is a place holder

    uint UninstallImageCodec();        // This is a place holder
}

/// <summary>
/// Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK
/// </summary>
[ComImport]
[Guid("327ABDAC-072B-11D3-9D7B-0000F81EF32E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IImageEncoder
{
    int InitEncoder(IStream stream);

    int TerminateEncoder();

    int GetEncodeSink();

    int SetFrameDimension(ref Guid dimensionID);

    int GetEncoderParameterListSize(out uint size);

    int GetEncoderParameterList(uint size, out IntPtr @params);

    int SetEncoderParameters(IntPtr param);
}

/// <summary>
/// This structure defines the coordinates of the upper-left and lower-right corners of a rectangle. 
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
    #region Fields

    public int left;

    public int top;

    public int right;

    public int bottom;

    #endregion
}

// Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK
internal enum BufferDisposalFlag : int
{
    BufferDisposalFlagNone,
    BufferDisposalFlagGlobalFree,
    BufferDisposalFlagCoTaskMemFree,
    BufferDisposalFlagUnmapView
}

// Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK
internal enum InterpolationHint : int
{
    InterpolationHintDefault,
    InterpolationHintNearestNeighbor,
    InterpolationHintBilinear,
    InterpolationHintAveraging,
    InterpolationHintBicubic
}

/// <summary>
/// These values are flags used to identify the numerical formats of pixels in images.
/// </summary>
[Flags]
public enum PixelFormatID
{
    PixelFormatIndexed = 0x00010000,

    PixelFormatGDI = 0x00020000,

    PixelFormatAlpha = 0x00040000,

    PixelFormatPAlpha = 0x00080000,

    PixelFormatExtended = 0x00100000,

    PixelFormatCanonical = 0x00200000,

    PixelFormatUndefined = 0,

    PixelFormat1bppIndexed = (1 | (1 << 8) | PixelFormatIndexed | PixelFormatGDI),

    PixelFormat4bppIndexed = (2 | (4 << 8) | PixelFormatIndexed | PixelFormatGDI),

    PixelFormat16bppGrayScale = (4 | (16 << 8) | PixelFormatExtended),

    PixelFormat8bppIndexed = (3 | (8 << 8) | PixelFormatIndexed | PixelFormatGDI),

    PixelFormat16bppRGB555 = (5 | (16 << 8) | PixelFormatGDI),

    PixelFormat16bppRGB565 = (6 | (16 << 8) | PixelFormatGDI),

    PixelFormat16bppARGB1555 = (7 | (16 << 8) | PixelFormatAlpha | PixelFormatGDI),

    PixelFormat24bppRGB = (8 | (24 << 8) | PixelFormatGDI),

    PixelFormat32bppRGB = (9 | (32 << 8) | PixelFormatGDI),

    PixelFormat32bppARGB = (10 | (32 << 8) | PixelFormatAlpha | PixelFormatGDI | PixelFormatCanonical),

    PixelFormat32bppPARGB = (11 | (32 << 8) | PixelFormatAlpha | PixelFormatPAlpha | PixelFormatGDI),

    PixelFormat48bppRGB = (12 | (48 << 8) | PixelFormatExtended),

    PixelFormat64bppARGB = (13 | (64 << 8) | PixelFormatAlpha | PixelFormatCanonical | PixelFormatExtended),

    PixelFormat64bppPARGB = (14 | (64 << 8) | PixelFormatAlpha | PixelFormatPAlpha | PixelFormatExtended),

    PixelFormatMax = 15
}

[Flags]
internal enum SinkFlags : uint
{
    // Low-word: shared with ImgFlagx
    Scalable = 0x0001,
    HasAlpha = 0x0002,
    HasTranslucent = 0x0004,
    PartiallyScalable = 0x0008,

    ColorSpaceRGB = 0x0010,
    ColorSpaceCMYK = 0x0020,
    ColorSpaceGRAY = 0x0040,
    ColorSpaceYCBCR = 0x0080,
    ColorSpaceYCCK = 0x0100,

    // Low-word: image size info
    HasRealDPI = 0x1000,
    HasRealPixelSize = 0x2000,

    // High-word
    TopDown = 0x00010000,
    BottomUp = 0x00020000,
    FullWidth = 0x00040000,
    Multipass = 0x00080000,
    Composite = 0x00100000,
    WantProps = 0x00200000
}

/// <summary>
/// Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK
/// </summary>
[ComImport]
[Guid("327ABDA9-072B-11D3-9D7B-0000F81EF32E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
internal interface IImage
{
    uint GetPhysicalDimension(out Size size);

    uint GetImageInfo(ref ImageInfo info);

    uint SetImageFlags(uint flags);

    // "Correct" declaration: uint Draw(IntPtr hdc, ref Rectangle dstRect, ref Rectangle srcRect);
    uint Draw(IntPtr hdc, ref RECT dstRect, IntPtr srcRect);

    uint PushIntoSink(); // This is a place holder

    uint GetThumbnail(uint thumbWidth, uint thumbHeight, out IImage thumbImage);
}

/// <summary>
/// Implmentation for the COM IStream interface
/// </summary>
public sealed class StreamOnFile :
    IStream,
    IDisposable
{
    #region Fields

    private readonly Stream stream;
    private readonly string fileName;

    #endregion

    #region Constructors

    /// <summary>
    ///     Initializes a new instance of the <see cref="StreamOnFile"/> class.
    /// </summary>
    /// <param name="fileName">File name to open
    /// </param>
    internal StreamOnFile(string fileName)
    {
        this.fileName = fileName;

        // prevent another processes/threads (mainly delete from web) from using this file while Imaging API is trying to access it
        this.stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None);
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets the file name
    /// </summary>
    public string FileName
    {
        get
        {
            return this.fileName;
        }
    }

    #endregion

    #region Methods

    public void Read(byte[] pv, int cb, IntPtr pcbRead)
    {
        int val = this.stream.Read(pv, 0, cb);
        if (pcbRead != IntPtr.Zero)
        {
            Marshal.WriteInt32(pcbRead, val);
        }
    }

    public void Write(byte[] pv, int cb, IntPtr pcbWritten)
    {
        this.stream.Write(pv, 0, cb);
        if (pcbWritten != IntPtr.Zero)
        {
            Marshal.WriteInt32(pcbWritten, cb);
        }
    }

    public void Seek(long dlibMove, int origin, IntPtr plibNewPosition)
    {
        long val = this.stream.Seek(dlibMove, (SeekOrigin)origin);
        if (plibNewPosition != IntPtr.Zero)
        {
            Marshal.WriteInt64(plibNewPosition, val);
        }
    }

    public void SetSize(long libNewSize)
    {
        throw new NotImplementedException("The method or operation is not implemented.");
    }

    public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
    {
        throw new NotImplementedException("The method or operation is not implemented.");
    }

    public void Commit(int grfCommitFlags)
    {
        throw new NotImplementedException("The method or operation is not implemented.");
    }

    public void Revert()
    {
        throw new NotImplementedException("The method or operation is not implemented.");
    }

    public void LockRegion(long libOffset, long cb, int lockType)
    {
        throw new NotImplementedException("The method or operation is not implemented.");
    }

    public void UnlockRegion(long libOffset, long cb, int lockType)
    {
        throw new NotImplementedException("The method or operation is not implemented.");
    }

    public void Stat(out STATSTG pstatstg, int grfStatFlag)
    {
        throw new NotImplementedException("The method or operation is not implemented.");
    }

    public void Clone(out IStream ppstm)
    {
        throw new NotImplementedException("The method or operation is not implemented.");
    }

    public void Dispose()
    {
        if (this.stream != null)
        {
            this.stream.Close();
        }
    }

    #endregion
}

public enum ImageType
{
    Undefined,
    MemoryBMP,
    BMP,
    EMF,
    WMF,
    JPEG,
    PNG,
    GIF,
    TIFF,
    EXIF,
    Icon
}

public static class BitmapProperties
{
    /// <summary>
    /// Indicates the Microsoft Windowsbitmap (BMP) format.
    /// </summary>
    private static readonly Guid ImageFormatBMP = new Guid("B96B3CAB-0728-11D3-9D7B-0000F81EF32E");

    /// <summary>
    /// Indicates the Enhanced Metafile (EMF) format.
    /// </summary>
    private static readonly Guid ImageFormatEMF = new Guid("B96B3CAC-0728-11D3-9D7B-0000F81EF32E");

    /// <summary>
    /// Indicates the Exif (Exchangeable Image File) format.
    /// </summary>
    private static readonly Guid ImageFormatEXIF = new Guid("B96B3CB2-0728-11D3-9D7B-0000F81EF32E");

    /// <summary>
    /// Indicates the Graphics Interchange Format (GIF) format.
    /// </summary>
    private static readonly Guid ImageFormatGIF = new Guid("B96B3CB0-0728-11D3-9D7B-0000F81EF32E");

    /// <summary>
    /// Indicates the Icon format.
    /// </summary>
    private static readonly Guid ImageFormatIcon = new Guid("B96B3CB5-0728-11D3-9D7B-0000F81EF32E");

    /// <summary>
    /// Indicates the JPEG format.
    /// </summary>
    private static readonly Guid ImageFormatJPEG = new Guid("B96B3CAE-0728-11D3-9D7B-0000F81EF32E");

    /// <summary>
    /// Indicates that the image was constructed from a memory bitmap.
    /// </summary>
    private static readonly Guid ImageFormatMemoryBMP = new Guid("B96B3CAB-0728-11D3-9D7B-0000F81EF32E");

    /// <summary>
    /// Indicates the Portable Network Graphics (PNG) format.
    /// </summary>
    private static readonly Guid ImageFormatPNG = new Guid("B96B3CAF-0728-11D3-9D7B-0000F81EF32E");

    /// <summary>
    /// Indicates the Tagged Image File Format (TIFF) format.
    /// </summary>
    private static readonly Guid ImageFormatTIFF = new Guid("B96B3CB1-0728-11D3-9D7B-0000F81EF32E");

    /// <summary>
    /// Indicates that Windows GDI+ is unable to determine the format.
    /// </summary>
    private static readonly Guid ImageFormatUndefined = new Guid("B96B3CA9-0728-11D3-9D7B-0000F81EF32E");

    /// <summary>
    /// Indicates the Windows Metafile Format (WMF) format.
    /// </summary>
    private static readonly Guid ImageFormatWMF = new Guid("B96B3CAD-0728-11D3-9D7B-0000F81EF32E");

    internal const int S_OK = 0;

    /// <summary>
    /// Gets the ImageType of the given file
    /// </summary>
    /// <param name="fileName">Path of the file to get the info of</param>
    /// <returns>ImageType of the given file</returns>
    public static ImageType GetImageType(string fileName)
    {
        IImage imagingImage = null;

        try
        {
            if (File.Exists(fileName))
            {
                using (StreamOnFile fileStream = new StreamOnFile(fileName))
                {
                    imagingImage = BitmapProperties.GetImage(fileStream);
                    if (imagingImage != null)
                    {
                        ImageInfo info = new ImageInfo();
                        uint ret = imagingImage.GetImageInfo(ref info);
                        if (ret == BitmapProperties.S_OK)
                        {
                            if (info.RawDataFormat == BitmapProperties.ImageFormatBMP)
                            {
                                return ImageType.BMP;
                            }
                            else if (info.RawDataFormat == BitmapProperties.ImageFormatEMF)
                            {
                                return ImageType.EMF;
                            }
                            else if (info.RawDataFormat == BitmapProperties.ImageFormatEXIF)
                            {
                                return ImageType.EXIF;
                            }
                            else if (info.RawDataFormat == BitmapProperties.ImageFormatGIF)
                            {
                                return ImageType.GIF;
                            }
                            else if (info.RawDataFormat == BitmapProperties.ImageFormatIcon)
                            {
                                return ImageType.Icon;
                            }
                            else if (info.RawDataFormat == BitmapProperties.ImageFormatJPEG)
                            {
                                return ImageType.JPEG;
                            }
                            else if (info.RawDataFormat == BitmapProperties.ImageFormatMemoryBMP)
                            {
                                return ImageType.MemoryBMP;
                            }
                            else if (info.RawDataFormat == BitmapProperties.ImageFormatPNG)
                            {
                                return ImageType.PNG;
                            }
                            else if (info.RawDataFormat == BitmapProperties.ImageFormatTIFF)
                            {
                                return ImageType.TIFF;
                            }
                            else if (info.RawDataFormat == BitmapProperties.ImageFormatWMF)
                            {
                                return ImageType.WMF;
                            }
                        }
                    }
                }
            }

            return ImageType.Undefined;
        }
        finally
        {
            if (imagingImage != null)
            {
                Marshal.ReleaseComObject(imagingImage);
            }
        }
    }

    private static IImage GetImage(StreamOnFile stream)
    {
        IImagingFactory factory = null;
        try
        {
            factory = (IImagingFactory)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("327ABDA8-072B-11D3-9D7B-0000F81EF32E")));
            if (factory != null)
            {
                IImage imagingImage;
                uint result = factory.CreateImageFromStream(stream, out imagingImage);
                if (result == BitmapProperties.S_OK)
                {
                    return imagingImage;
                }
            }
        }
        catch (COMException)
        {
        }
        catch (IOException)
        {
        }
        finally
        {
            if (factory != null)
            {
                Marshal.ReleaseComObject(factory);
            }
        }

        return null;
    }
}

答案 3 :(得分:1)

将字节数组解析为实际的图像对象可能会占用大量资源,尤其是对于大量数据而言

您可以改用Magic Numbers

  

JPEG图像文件以FF D8开头,以FF D9结尾

...

  

PNG图像文件以8字节签名开头,用于标识   文件作为PNG文件,并允许检测常见文件传输   问题:(89 50 4E 47 0D 0A 1A 0A)

一些适合您的示例代码:

public bool IsPng(byte[] array)
{
    return array != null
        && array.Length > 8
        && array[0] == 0x89
        && array[1] == 0x50
        && array[2] == 0x4e
        && array[3] == 0x47
        && array[4] == 0x0d
        && array[5] == 0x0a
        && array[6] == 0x1a
        && array[7] == 0x0a
}

当然,您应该在进行此快速检查后进一步验证数据,以100%确定格式是安全的并且是实际图像。

P.S。这是浏览器的方式

答案 4 :(得分:1)

这是我根据 Alex 提到的方法和参考文章编写的一个非常轻量级的 ImageDetector 类:

namespace ImageDetection
{
    using System;
    using System.Collections.Generic;
    using System.Drawing.Imaging;
    using System.Linq;

    // based on https://devblogs.microsoft.com/scripting/psimaging-part-1-test-image/
    public class ImageDetector
    {
        // https://en.wikipedia.org/wiki/List_of_file_signatures
        /* Bytes in c# have a range of 0 to 255 so each byte can be represented as
         * a two digit hex string. */
        private static readonly Dictionary<ImageFormat, string[][]> SignatureTable = new Dictionary<ImageFormat, string[][]>
        {
            {
                ImageFormat.Jpeg,
                new[]
                {
                    new[] {"FF", "D8", "FF", "DB"},
                    new[] {"FF", "D8", "FF", "EE"},
                    new[] {"FF", "D8", "FF", "E0", "00", "10", "4A", "46", "49", "46", "00", "01"}
                }
            },
            {
                ImageFormat.Gif,
                new[]
                {
                    new [] { "47", "49", "46", "38", "37", "61" },
                    new [] { "47", "49", "46", "38", "39", "61" }
                }
            },
            {
                ImageFormat.Png,
                new[]
                {
                    new[] {"89", "50", "4E", "47", "0D", "0A", "1A", "0A"}
                }
            },
            {
                ImageFormat.Bmp,
                new []
                {
                    new[] { "42", "4D" }
                }
            }
        };
        
        /// <summary>
        /// Takes a byte array and determines the image file type by
        /// comparing the first few bytes of the file to a list of known
        /// image file signatures.
        /// </summary>
        /// <param name="imageData">Byte array of the image data</param>
        /// <returns>ImageFormat corresponding to the image file format</returns>
        /// <exception cref="ArgumentException">Thrown if the image type can't be determined</exception>
        public static ImageFormat GetImageType(byte[] imageData)
        {
            foreach (KeyValuePair<ImageFormat, string[][]> signatureEntry in SignatureTable)
            {
                foreach (string[] signature in signatureEntry.Value)
                {
                    bool isMatch = true;
                    for (int i = 0; i < signature.Length; i++)
                    {
                        string signatureByte = signature[i];
                    
                        // ToString("X") gets the hex representation and pads it to always be length 2
                        string imageByte = imageData[i]
                            .ToString("X2");

                        if (signatureByte == imageByte)
                            continue;
                        isMatch = false;
                        break;
                    }

                    if (isMatch)
                    {
                        return signatureEntry.Key;
                    }
                }
            }
            
            throw new ArgumentException("The byte array did not match any known image file signatures.");
        }
    }
    
    
}

答案 5 :(得分:1)

我需要一个简单的 Java 图像格式检测器(用于 Android 应用程序),因此改编 @Jared_Beach 答案,还添加了 WebP 格式检测:

import com.sun.istack.internal.Nullable;

// based on https://devblogs.microsoft.com/scripting/psimaging-part-1-test-image/
public class ImageDetector
{
    final static String[] imgFormats = {"jpg", "gif", "png", "bmp", "webp"};

    private enum ImageFormat {
        Jpeg (new int[][]{
                {0xFF, 0xD8, 0xFF, 0xDB},
                {0xFF, 0xD8, 0xFF, 0xEE},
                {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01}
        }),
        Gif (new int[][]{
                {0x47, 0x49, 0x46, 0x38, 0x37, 0x61},
                {0x47, 0x49, 0x46, 0x38, 0x39, 0x61}
        }),
        Png (new int[][]{
                {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}
        }),
        Bmp (new int[][]{
                {0x42, 0x4D}
        }),
        WebP (new int[][]{
                // Ignores zeroes - image size goes there
                { 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P'}
        });

        final byte[][] _bts;

        ImageFormat(int[][] b) {
            _bts = new byte[b.length][];
            for (int i = 0; i < b.length; i++) {
                _bts[i] = new byte[b[i].length];
                for (int j = 0; j < b[i].length; j++)
                    _bts[i][j] = (byte) b[i][j];
            }
        }
    }

    /**
     Takes a byte array and determines the image file type by
     comparing the first few bytes of the file to a list of known
     image file signatures.

     @param imageData Byte array of the image data
     @return type from imgFormats, it can be a MIME too type with "image/"+imgFormats[i], or simply file name extension,
             or null if type not recognized.
     */
    @Nullable
    public static String getImageType(byte[] imageData)
    {
        if (imageData.length > 16) { // too small, avoid index out of bounds exception
            for (ImageFormat imgF : ImageFormat.values()) {
                for (byte[] sig : imgF._bts) {
                    boolean isMatch = true;
                    for (int i = 0; i < sig.length; i++) {
                        if ((sig[i] != 0 || imgF != ImageFormat.WebP) && sig[i] != imageData[i]) {
                            isMatch = false;
                            break;
                        }
                    }
                    if (isMatch)
                        return imgFormats[imgF.ordinal()];
                }
            }
        }
        return null;
    }
}

这是一个小测试函数:

static void testImageDetector() {
    final String[] fileNames = {
            "C:/tmp/test.jpg",
            "C:/tmp/test.gif",
            "C:/tmp/test.png",
            "C:/tmp/test.bmp",
            "C:/tmp/test.webp",
    };
    FileInputStream fis = null;
    try {
        byte[] buf = new byte[64];
        String type;
        for (String fName : fileNames) {
            fis = new FileInputStream(fName);
            fis.read(buf);
            fis.close(); fis = null;
            String ext = fName.substring(fName.lastIndexOf('.') + 1);
            type = ImageDetector.getImageType(buf);
            System.out.println("File: " + fName + ", type: " + type);
            if (!ext.equals(type))
                throw new AssertionError("Wrong type detected!");
        }
    }
    catch (IOException iox) {
        System.out.println("IOException: " + iox);
        iox.printStackTrace();
    }
    catch (AssertionError ae) {
        ae.printStackTrace();
    }
    finally {
        if (fis != null) try {
            fis.close();
        } catch (IOException ignore) {}
    }
}