Introduction
In C#, the System.Drawing.Bitmap class provides the RawFormat property to determine an image's format (JPEG, PNG, GIF, BMP, TIFF, etc.) after loading it from a file or stream. This is useful when processing user-uploaded images where the file extension may be incorrect or missing, or when handling images from streams and byte arrays where no filename exists. The RawFormat property returns an ImageFormat object that you compare against known format constants like ImageFormat.Jpeg and ImageFormat.Png.
1using System.Drawing;
2using System.Drawing.Imaging;
3
4// Load an image and check its format
5using (Bitmap bitmap = new Bitmap("photo.jpg"))
6{
7 ImageFormat format = bitmap.RawFormat;
8
9 if (format.Equals(ImageFormat.Jpeg))
10 Console.WriteLine("Format: JPEG");
11 else if (format.Equals(ImageFormat.Png))
12 Console.WriteLine("Format: PNG");
13 else if (format.Equals(ImageFormat.Gif))
14 Console.WriteLine("Format: GIF");
15 else if (format.Equals(ImageFormat.Bmp))
16 Console.WriteLine("Format: BMP");
17 else if (format.Equals(ImageFormat.Tiff))
18 Console.WriteLine("Format: TIFF");
19 else if (format.Equals(ImageFormat.Icon))
20 Console.WriteLine("Format: ICO");
21 else
22 Console.WriteLine($"Unknown format: {format.Guid}");
23}
RawFormat detects the actual binary format of the image data, regardless of the file extension. A file named photo.png that is actually a JPEG will correctly report as JPEG.
1using System.Drawing;
2using System.Drawing.Imaging;
3
4public static class ImageFormatHelper
5{
6 public static string GetImageFormat(Bitmap bitmap)
7 {
8 if (ImageFormat.Jpeg.Equals(bitmap.RawFormat)) return "JPEG";
9 if (ImageFormat.Png.Equals(bitmap.RawFormat)) return "PNG";
10 if (ImageFormat.Gif.Equals(bitmap.RawFormat)) return "GIF";
11 if (ImageFormat.Bmp.Equals(bitmap.RawFormat)) return "BMP";
12 if (ImageFormat.Tiff.Equals(bitmap.RawFormat)) return "TIFF";
13 if (ImageFormat.Icon.Equals(bitmap.RawFormat)) return "ICO";
14 if (ImageFormat.Emf.Equals(bitmap.RawFormat)) return "EMF";
15 if (ImageFormat.Wmf.Equals(bitmap.RawFormat)) return "WMF";
16 return "Unknown";
17 }
18
19 public static string GetFileExtension(Bitmap bitmap)
20 {
21 if (ImageFormat.Jpeg.Equals(bitmap.RawFormat)) return ".jpg";
22 if (ImageFormat.Png.Equals(bitmap.RawFormat)) return ".png";
23 if (ImageFormat.Gif.Equals(bitmap.RawFormat)) return ".gif";
24 if (ImageFormat.Bmp.Equals(bitmap.RawFormat)) return ".bmp";
25 if (ImageFormat.Tiff.Equals(bitmap.RawFormat)) return ".tiff";
26 if (ImageFormat.Icon.Equals(bitmap.RawFormat)) return ".ico";
27 return ".bin";
28 }
29}
30
31// Usage
32using (var bmp = new Bitmap("unknown_file"))
33{
34 Console.WriteLine($"Format: {ImageFormatHelper.GetImageFormat(bmp)}");
35 Console.WriteLine($"Extension: {ImageFormatHelper.GetFileExtension(bmp)}");
36}
1using System.Drawing;
2using System.Drawing.Imaging;
3using System.IO;
4
5// From a file stream
6using (FileStream fs = new FileStream("image.dat", FileMode.Open))
7using (Bitmap bitmap = new Bitmap(fs))
8{
9 string format = ImageFormatHelper.GetImageFormat(bitmap);
10 Console.WriteLine($"Stream image format: {format}");
11}
12
13// From a byte array (e.g., from a database or HTTP response)
14byte[] imageBytes = File.ReadAllBytes("photo.jpg");
15using (MemoryStream ms = new MemoryStream(imageBytes))
16using (Bitmap bitmap = new Bitmap(ms))
17{
18 string format = ImageFormatHelper.GetImageFormat(bitmap);
19 Console.WriteLine($"Byte array image format: {format}");
20}
When loading from streams, Bitmap reads the binary header to detect the format. The stream must remain open for the lifetime of the Bitmap object.
Using ImageCodecInfo for MIME Type
1using System.Drawing;
2using System.Drawing.Imaging;
3using System.Linq;
4
5public static string GetMimeType(Bitmap bitmap)
6{
7 ImageCodecInfo codec = ImageCodecInfo.GetImageDecoders()
8 .FirstOrDefault(c => c.FormatID == bitmap.RawFormat.Guid);
9
10 return codec?.MimeType ?? "application/octet-stream";
11}
12
13// Usage
14using (var bmp = new Bitmap("photo.jpg"))
15{
16 Console.WriteLine(GetMimeType(bmp)); // "image/jpeg"
17}
ImageCodecInfo.GetImageDecoders() returns all registered image codecs. Matching by FormatID gives you the MIME type (image/jpeg, image/png, etc.), which is useful for HTTP content-type headers.
1// System.Drawing is Windows-only in .NET Core/.NET 5+
2// Use SixLabors.ImageSharp for cross-platform support
3
4// Install: dotnet add package SixLabors.ImageSharp
5
6using SixLabors.ImageSharp;
7using SixLabors.ImageSharp.Formats;
8
9IImageFormat format;
10using (Image image = Image.Load("photo.jpg", out format))
11{
12 Console.WriteLine($"Format: {format.Name}"); // "JPEG"
13 Console.WriteLine($"MIME: {format.DefaultMimeType}"); // "image/jpeg"
14 Console.WriteLine($"Size: {image.Width}x{image.Height}");
15}
16
17// Detect format without loading the full image
18IImageFormat detectedFormat = Image.DetectFormat("photo.jpg");
19Console.WriteLine(detectedFormat?.Name); // "JPEG"
ImageSharp is the recommended replacement for System.Drawing in cross-platform .NET applications. It detects format directly during load and provides a clean API.
Reading Magic Bytes (Without Loading the Image)
1using System.IO;
2
3public static string DetectFormatByMagicBytes(string filePath)
4{
5 byte[] header = new byte[8];
6 using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
7 {
8 fs.Read(header, 0, header.Length);
9 }
10
11 // JPEG: FF D8 FF
12 if (header[0] == 0xFF && header[1] == 0xD8 && header[2] == 0xFF)
13 return "JPEG";
14
15 // PNG: 89 50 4E 47 0D 0A 1A 0A
16 if (header[0] == 0x89 && header[1] == 0x50 && header[2] == 0x4E && header[3] == 0x47)
17 return "PNG";
18
19 // GIF: 47 49 46 38
20 if (header[0] == 0x47 && header[1] == 0x49 && header[2] == 0x46)
21 return "GIF";
22
23 // BMP: 42 4D
24 if (header[0] == 0x42 && header[1] == 0x4D)
25 return "BMP";
26
27 return "Unknown";
28}
Magic bytes detection reads only the first few bytes of the file, making it much faster than loading the entire image into a Bitmap object. This is ideal for validating uploads before processing.
Common Pitfalls
Using == instead of .Equals() to compare ImageFormat: bitmap.RawFormat == ImageFormat.Jpeg compares references, not values, and may return false even for JPEG images. Always use bitmap.RawFormat.Equals(ImageFormat.Jpeg) or compare the Guid property.
Using System.Drawing on Linux or macOS: System.Drawing.Bitmap depends on GDI+ (Windows-only). On .NET Core/.NET 5+ non-Windows platforms, it throws PlatformNotSupportedException. Use SixLabors.ImageSharp or SkiaSharp for cross-platform applications.
Not disposing the Bitmap: Bitmap holds unmanaged GDI+ resources. Failing to call Dispose() (or use a using block) causes memory leaks, especially when processing many images in a loop.
Closing the source stream before the Bitmap: When loading from a Stream, the stream must remain open for the Bitmap's lifetime. Closing the stream prematurely causes GDI+ generic error exceptions on subsequent operations.
Trusting file extensions for format detection: File extensions can be wrong or spoofed. A file named .png may contain JPEG data. Always use RawFormat or magic bytes to detect the actual format, especially for user-uploaded files in security-sensitive contexts.
Summary
Use bitmap.RawFormat.Equals(ImageFormat.Jpeg) to check the image format
RawFormat detects the actual binary format, not the file extension
Use ImageCodecInfo to get the MIME type from the format GUID
For cross-platform .NET, use SixLabors.ImageSharp instead of System.Drawing
Magic bytes detection is fastest when you only need the format without loading the full image
Always use using blocks with Bitmap to prevent GDI+ resource leaks