117

Is there a cheap way to get the dimensions of an image (jpg, png, ...)? Preferably, I would like to achieve this using only the standard class library (because of hosting restrictions). I know that it should be relatively easy to read the image header and parse it myself, but it seems that something like this should be already there. Also, I’ve verified that the following piece of code reads the entire image (which I don’t want):

using System;
using System.Drawing;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Image img = new Bitmap("test.png");
            System.Console.WriteLine(img.Width + " x " + img.Height);
        }
    }
}
Jan Zich
  • 14,993
  • 18
  • 61
  • 73
  • It would help if you were a bit more specific in the question proper. The tags have told me .net and c#, and you want standard library, but what are these hosting restrictions you mentions? – wnoise Sep 21 '08 at 20:29
  • If you have access to the System.Windows.Media.Imaging namespace (in WPF), see this SO question: http://stackoverflow.com/questions/784734/using-wpf-imaging-classes-getting-image-dimensions-without-reading-the-entire?lq=1 – Charlie Dec 06 '13 at 00:18

9 Answers9

116

Your best bet as always is to find a well tested library. However, you said that is difficult, so here is some dodgy largely untested code that should work for a fair number of cases:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;

namespace ImageDimensions
{
    public static class ImageHelper
    {
        const string errorMessage = "Could not recognize image format.";

        private static Dictionary<byte[], Func<BinaryReader, Size>> imageFormatDecoders = new Dictionary<byte[], Func<BinaryReader, Size>>()
        {
            { new byte[]{ 0x42, 0x4D }, DecodeBitmap},
            { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
            { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
            { new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
            { new byte[]{ 0xff, 0xd8 }, DecodeJfif },
        };

        /// <summary>
        /// Gets the dimensions of an image.
        /// </summary>
        /// <param name="path">The path of the image to get the dimensions of.</param>
        /// <returns>The dimensions of the specified image.</returns>
        /// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>
        public static Size GetDimensions(string path)
        {
            using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(path)))
            {
                try
                {
                    return GetDimensions(binaryReader);
                }
                catch (ArgumentException e)
                {
                    if (e.Message.StartsWith(errorMessage))
                    {
                        throw new ArgumentException(errorMessage, "path", e);
                    }
                    else
                    {
                        throw e;
                    }
                }
            }
        }

        /// <summary>
        /// Gets the dimensions of an image.
        /// </summary>
        /// <param name="path">The path of the image to get the dimensions of.</param>
        /// <returns>The dimensions of the specified image.</returns>
        /// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>    
        public static Size GetDimensions(BinaryReader binaryReader)
        {
            int maxMagicBytesLength = imageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;

            byte[] magicBytes = new byte[maxMagicBytesLength];

            for (int i = 0; i < maxMagicBytesLength; i += 1)
            {
                magicBytes[i] = binaryReader.ReadByte();

                foreach(var kvPair in imageFormatDecoders)
                {
                    if (magicBytes.StartsWith(kvPair.Key))
                    {
                        return kvPair.Value(binaryReader);
                    }
                }
            }

            throw new ArgumentException(errorMessage, "binaryReader");
        }

        private static bool StartsWith(this byte[] thisBytes, byte[] thatBytes)
        {
            for(int i = 0; i < thatBytes.Length; i+= 1)
            {
                if (thisBytes[i] != thatBytes[i])
                {
                    return false;
                }
            }
            return true;
        }

        private static short ReadLittleEndianInt16(this BinaryReader binaryReader)
        {
            byte[] bytes = new byte[sizeof(short)];
            for (int i = 0; i < sizeof(short); i += 1)
            {
                bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte();
            }
            return BitConverter.ToInt16(bytes, 0);
        }

        private static int ReadLittleEndianInt32(this BinaryReader binaryReader)
        {
            byte[] bytes = new byte[sizeof(int)];
            for (int i = 0; i < sizeof(int); i += 1)
            {
                bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte();
            }
            return BitConverter.ToInt32(bytes, 0);
        }

        private static Size DecodeBitmap(BinaryReader binaryReader)
        {
            binaryReader.ReadBytes(16);
            int width = binaryReader.ReadInt32();
            int height = binaryReader.ReadInt32();
            return new Size(width, height);
        }

        private static Size DecodeGif(BinaryReader binaryReader)
        {
            int width = binaryReader.ReadInt16();
            int height = binaryReader.ReadInt16();
            return new Size(width, height);
        }

        private static Size DecodePng(BinaryReader binaryReader)
        {
            binaryReader.ReadBytes(8);
            int width = binaryReader.ReadLittleEndianInt32();
            int height = binaryReader.ReadLittleEndianInt32();
            return new Size(width, height);
        }

        private static Size DecodeJfif(BinaryReader binaryReader)
        {
            while (binaryReader.ReadByte() == 0xff)
            {
                byte marker = binaryReader.ReadByte();
                short chunkLength = binaryReader.ReadLittleEndianInt16();

                if (marker == 0xc0)
                {
                    binaryReader.ReadByte();

                    int height = binaryReader.ReadLittleEndianInt16();
                    int width = binaryReader.ReadLittleEndianInt16();
                    return new Size(width, height);
                }

                binaryReader.ReadBytes(chunkLength - 2);
            }

            throw new ArgumentException(errorMessage);
        }
    }
}

Hopefully the code is fairly obvious. To add a new file format you add it to imageFormatDecoders with the key being an array of the "magic bits" which appear at the beginning of every file of the given format and the value being a function which extracts the size from the stream. Most formats are simple enough, the only real stinker is jpeg.

Robert
  • 1,286
  • 1
  • 17
  • 37
ICR
  • 13,896
  • 4
  • 50
  • 78
  • 8
    Agreed, JPEG sucks. Btw - a note for the people who want to use this code in the future: this is indeed untested. I've gone through it with a fine comb, and here's what I found: BMP format has another (ancient) header variation where dimensions are 16-bit; plus height can be negative (drop the sign then). As for JPEG - 0xC0 isn't the only header. Basically all of 0xC0 to 0xCF except 0xC4 and 0xCC are valid headers (you can easily get them in interlaced JPGs). And, to make things more fun, height can be 0 and specified later in a 0xDC block. See http://www.w3.org/Graphics/JPEG/itu-t81.pdf – Vilx- Feb 22 '11 at 12:36
  • Tweaked the DecodeJfif method above to expand the original (marker == 0xC0) check to accept 0xC1 and 0xC2 as well. These other start-of-frame headers SOF1 and SOF2 encode width/height in the same byte positions. SOF2 is fairly common. – Ryan Barton Nov 13 '14 at 20:03
  • 6
    Standard warning: You should never write `throw e;` but simply `throw;` instead. Your XML doc comments on the second `GetDimensions` also show `path` instead of `binaryReader` – Eregrith Jul 22 '15 at 14:18
  • @RyanBarton Can you post your code changes please? It will really help me a lot with similar problem. Thanks. – Steve Johnson Dec 28 '16 at 09:55
  • @SteveJohnson: edited code to include SOF1/SOF2 checks in DecodeJfif. – Ryan Barton Jan 18 '17 at 16:07
  • 1
    Also, seems this code doesn't accept JPEGs encoded in EXIF/TIFF format which is output by many digital cameras. It only supports JFIF. – cwills Aug 01 '18 at 02:36
  • 4
    System.Drawing.Image.FromStream(stream, false, false) will give you the dimensions without loading the entire image, and it works on any image .Net can load. Why this messy and incomplete solution has so many upvotes is beyond understanding. – dynamichael Nov 23 '18 at 20:29
  • 2
    @dynamichael there can be situations when you don't have access to that lib, so these solutions are needed. – MattyMatt Jan 10 '20 at 07:47
  • @MattyMatt2 From the OP: "Preferably, I would like to achieve this using only the standard class library" – dynamichael Jan 12 '20 at 10:20
  • 4
    @dynamichael `System.Drawing` is _not_ a standard library these days; it relies on GDI+, and there are plenty of c# platforms on which it is not available. – Nyerguds Sep 23 '20 at 10:43
  • 1
    By the way, `BinaryReader` is specifically specced to read little endian. The helper functions are unnecessary. In fact, you need a big-endian read for the PNG part; png internals are all big-endian. – Nyerguds Sep 23 '20 at 11:42
  • @RyanBarton: Am I missing something? I checked the revisions (https://stackoverflow.com/posts/112711/revisions) and the only changes made were spelling changes. No changes were made in the DecodeJfif method. – Anomalous Underdog Apr 04 '21 at 13:20
37
using (FileStream file = new FileStream(this.ImageFileName, FileMode.Open, FileAccess.Read))
{
    using (Image tif = Image.FromStream(stream: file, 
                                        useEmbeddedColorManagement: false,
                                        validateImageData: false))
    {
        float width = tif.PhysicalDimension.Width;
        float height = tif.PhysicalDimension.Height;
        float hresolution = tif.HorizontalResolution;
        float vresolution = tif.VerticalResolution;
     }
}

the validateImageData set to false prevents GDI+ from performing costly analysis of the image data, thus severely decreasing load time. This question sheds more light on the subject.

Community
  • 1
  • 1
Koray
  • 1,768
  • 1
  • 27
  • 37
  • 1
    I used your solution as last resource mixed with ICR's solution up above. Had problems with JPEG, and solved with this. – Zorkind Sep 11 '13 at 16:35
  • 2
    I recently tried this in a project where I had to query the size of 2000+ images (jpg and png mostly, very mixed sizes), and it was indeed much faster than the traditional way using `new Bitmap()`. – AeonOfTime Oct 24 '17 at 12:39
  • 2
    Best answer. Quick, clean, and effective. – dynamichael Nov 23 '18 at 20:31
  • 1
    This function is perfect on windows. but it not working on linux, it will still read entire file on linux. (.net core 2.2) – zhengchun Jan 10 '19 at 07:12
21

Have you tried using the WPF Imaging classes? System.Windows.Media.Imaging.BitmapDecoder, etc.?

I believe some effort was into making sure those codecs only read a subset of the file in order to determine header information. It's worth a check.

Frank Krueger
  • 69,552
  • 46
  • 163
  • 208
  • Thank you. It seems reasonable, but my hosting has .NET 2. – Jan Zich Sep 21 '08 at 16:50
  • 1
    Excellent answer. If you can get a reference to PresentationCore in your project, this is the way to go. – ojrac Jan 11 '10 at 17:18
  • In my unit tests, these classes don't perform any better than GDI... still require ~32K to read JPEGs dimensions. – Nariman Apr 20 '12 at 13:53
  • So to get the OP's image dimensions, how do you use the BitmapDecoder? – Chuck Savage Oct 22 '13 at 04:47
  • 1
    See this SO question: http://stackoverflow.com/questions/784734/using-wpf-imaging-classes-getting-image-dimensions-without-reading-the-entire?lq=1 – Charlie Dec 06 '13 at 00:18
14

I was looking for something similar a few months earlier. I wanted to read the type, version, height and width of a GIF image but couldn’t find anything useful online.

Fortunately in case of GIF, all the required information was in the first 10 bytes:

Type: Bytes 0-2
Version: Bytes 3-5
Height: Bytes 6-7
Width: Bytes 8-9

PNG are slightly more complex (width and height are 4-bytes each):

Width: Bytes 16-19
Height: Bytes 20-23

As mentioned above, wotsit is a good site for detailed specs on image and data formats though the PNG specs at pnglib are much more detailed. However, I think the Wikipedia entry on PNG and GIF formats is the best place to start.

Here’s my original code for checking GIFs, I have also slapped together something for PNGs:

using System;
using System.IO;
using System.Text;

public class ImageSizeTest
{
    public static void Main()
    {
        byte[] bytes = new byte[10];

        string gifFile = @"D:\Personal\Images&Pics\iProduct.gif";
        using (FileStream fs = File.OpenRead(gifFile))
        {
            fs.Read(bytes, 0, 10); // type (3 bytes), version (3 bytes), width (2 bytes), height (2 bytes)
        }
        displayGifInfo(bytes);

        string pngFile = @"D:\Personal\Images&Pics\WaveletsGamma.png";
        using (FileStream fs = File.OpenRead(pngFile))
        {
            fs.Seek(16, SeekOrigin.Begin); // jump to the 16th byte where width and height information is stored
            fs.Read(bytes, 0, 8); // width (4 bytes), height (4 bytes)
        }
        displayPngInfo(bytes);
    }

    public static void displayGifInfo(byte[] bytes)
    {
        string type = Encoding.ASCII.GetString(bytes, 0, 3);
        string version = Encoding.ASCII.GetString(bytes, 3, 3);

        int width = bytes[6] | bytes[7] << 8; // byte 6 and 7 contain the width but in network byte order so byte 7 has to be left-shifted 8 places and bit-masked to byte 6
        int height = bytes[8] | bytes[9] << 8; // same for height

        Console.WriteLine("GIF\nType: {0}\nVersion: {1}\nWidth: {2}\nHeight: {3}\n", type, version, width, height);
    }

    public static void displayPngInfo(byte[] bytes)
    {
        int width = 0, height = 0;

        for (int i = 0; i <= 3; i++)
        {
            width = bytes[i] | width << 8;
            height = bytes[i + 4] | height << 8;            
        }

        Console.WriteLine("PNG\nWidth: {0}\nHeight: {1}\n", width, height);  
    }
}
Abbas
  • 6,720
  • 4
  • 35
  • 49
8

Based on the answers so far and some additional searching, it seems that in the .NET 2 class library there is no functionality for it. So I decided to write my own. Here is a very rough version of it. At the moment, I needed it only for JPG’s. So it completes the answer posted by Abbas.

There is no error checking or any other verification, but I currently need it for a limited task, and it can be eventually easily added. I tested it on some number of images, and it usually does not read more that 6K from an image. I guess it depends on the amount of the EXIF data.

using System;
using System.IO;

namespace Test
{

    class Program
    {

        static bool GetJpegDimension(
            string fileName,
            out int width,
            out int height)
        {

            width = height = 0;
            bool found = false;
            bool eof = false;

            FileStream stream = new FileStream(
                fileName,
                FileMode.Open,
                FileAccess.Read);

            BinaryReader reader = new BinaryReader(stream);

            while (!found || eof)
            {

                // read 0xFF and the type
                reader.ReadByte();
                byte type = reader.ReadByte();

                // get length
                int len = 0;
                switch (type)
                {
                    // start and end of the image
                    case 0xD8: 
                    case 0xD9: 
                        len = 0;
                        break;

                    // restart interval
                    case 0xDD: 
                        len = 2;
                        break;

                    // the next two bytes is the length
                    default: 
                        int lenHi = reader.ReadByte();
                        int lenLo = reader.ReadByte();
                        len = (lenHi << 8 | lenLo) - 2;
                        break;
                }

                // EOF?
                if (type == 0xD9)
                    eof = true;

                // process the data
                if (len > 0)
                {

                    // read the data
                    byte[] data = reader.ReadBytes(len);

                    // this is what we are looking for
                    if (type == 0xC0)
                    {
                        width = data[1] << 8 | data[2];
                        height = data[3] << 8 | data[4];
                        found = true;
                    }

                }

            }

            reader.Close();
            stream.Close();

            return found;

        }

        static void Main(string[] args)
        {
            foreach (string file in Directory.GetFiles(args[0]))
            {
                int w, h;
                GetJpegDimension(file, out w, out h);
                System.Console.WriteLine(file + ": " + w + " x " + h);
            }
        }

    }
}
Jan Zich
  • 14,993
  • 18
  • 61
  • 73
6

Updated ICR's answer to support progressive jPegs & WebP as well :)

internal static class ImageHelper
{
    const string errorMessage = "Could not recognise image format.";

    private static Dictionary<byte[], Func<BinaryReader, Size>> imageFormatDecoders = new Dictionary<byte[], Func<BinaryReader, Size>>()
    {
        { new byte[] { 0x42, 0x4D }, DecodeBitmap },
        { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
        { new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
        { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
        { new byte[] { 0xff, 0xd8 }, DecodeJfif },
        { new byte[] { 0x52, 0x49, 0x46, 0x46 }, DecodeWebP },
    };

    /// <summary>        
    /// Gets the dimensions of an image.        
    /// </summary>        
    /// <param name="path">The path of the image to get the dimensions of.</param>        
    /// <returns>The dimensions of the specified image.</returns>        
    /// <exception cref="ArgumentException">The image was of an unrecognised format.</exception>            
    public static Size GetDimensions(BinaryReader binaryReader)
    {
        int maxMagicBytesLength = imageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;
        byte[] magicBytes = new byte[maxMagicBytesLength];
        for(int i = 0; i < maxMagicBytesLength; i += 1)
        {
            magicBytes[i] = binaryReader.ReadByte();
            foreach(var kvPair in imageFormatDecoders)
            {
                if(StartsWith(magicBytes, kvPair.Key))
                {
                    return kvPair.Value(binaryReader);
                }
            }
        }

        throw new ArgumentException(errorMessage, "binaryReader");
    }

    private static bool StartsWith(byte[] thisBytes, byte[] thatBytes)
    {
        for(int i = 0; i < thatBytes.Length; i += 1)
        {
            if(thisBytes[i] != thatBytes[i])
            {
                return false;
            }
        }

        return true;
    }

    private static short ReadLittleEndianInt16(BinaryReader binaryReader)
    {
        byte[] bytes = new byte[sizeof(short)];

        for(int i = 0; i < sizeof(short); i += 1)
        {
            bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte();
        }
        return BitConverter.ToInt16(bytes, 0);
    }

    private static int ReadLittleEndianInt32(BinaryReader binaryReader)
    {
        byte[] bytes = new byte[sizeof(int)];
        for(int i = 0; i < sizeof(int); i += 1)
        {
            bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte();
        }
        return BitConverter.ToInt32(bytes, 0);
    }

    private static Size DecodeBitmap(BinaryReader binaryReader)
    {
        binaryReader.ReadBytes(16);
        int width = binaryReader.ReadInt32();
        int height = binaryReader.ReadInt32();
        return new Size(width, height);
    }

    private static Size DecodeGif(BinaryReader binaryReader)
    {
        int width = binaryReader.ReadInt16();
        int height = binaryReader.ReadInt16();
        return new Size(width, height);
    }

    private static Size DecodePng(BinaryReader binaryReader)
    {
        binaryReader.ReadBytes(8);
        int width = ReadLittleEndianInt32(binaryReader);
        int height = ReadLittleEndianInt32(binaryReader);
        return new Size(width, height);
    }

    private static Size DecodeJfif(BinaryReader binaryReader)
    {
        while(binaryReader.ReadByte() == 0xff)
        {
            byte marker = binaryReader.ReadByte();
            short chunkLength = ReadLittleEndianInt16(binaryReader);
            if(marker == 0xc0 || marker == 0xc2) // c2: progressive
            {
                binaryReader.ReadByte();
                int height = ReadLittleEndianInt16(binaryReader);
                int width = ReadLittleEndianInt16(binaryReader);
                return new Size(width, height);
            }

            if(chunkLength < 0)
            {
                ushort uchunkLength = (ushort)chunkLength;
                binaryReader.ReadBytes(uchunkLength - 2);
            }
            else
            {
                binaryReader.ReadBytes(chunkLength - 2);
            }
        }

        throw new ArgumentException(errorMessage);
    }

    private static Size DecodeWebP(BinaryReader binaryReader)
    {
        binaryReader.ReadUInt32(); // Size
        binaryReader.ReadBytes(15); // WEBP, VP8 + more
        binaryReader.ReadBytes(3); // SYNC

        var width = binaryReader.ReadUInt16() & 0b00_11111111111111; // 14 bits width
        var height = binaryReader.ReadUInt16() & 0b00_11111111111111; // 14 bits height

        return new Size(width, height);
    }

}
bang
  • 4,982
  • 1
  • 24
  • 28
  • Thanks for getting webp started. DecodeWebP works only for Webp Lossy images - https://developers.google.com/speed/webp/gallery1 – Markus Sep 17 '20 at 19:49
  • The internals of png are all big-endian (gif too, I believe). And `BinaryReader` always reads little-endian anyway, regardless of system endianness, so the existing helper functions are useless. – Nyerguds Sep 23 '20 at 11:47
  • I cant seem to get any jpeg i try to decode using this example or the other; after it reads the 0xff, the next bytes are not C0 or C2 so it just jumps straight out or fails trying to read beyond end of stream – Samuel Johnson Dec 14 '21 at 22:46
  • @SamuelJohnson Possible reasons : Most likely, your jpegs only have SOF1 and SOF2 segments (requires 0xC1 and 0xC2 equality on the marker check - edit your code, it's missing here). Possibly, you made some changes, or your copy is incomplete, which may lead to the logic exiting the loop prematurely. Or, your system is bigEndian (BE) : the littleEndian (LE) functions here are not reading LE data, they are converting BE data from the jpeg to LE and works only on a LE system like on a Windows PC. On a BE system, you'll likely never find the SOF segment and exceed the length of the file. – Karl Stephen Apr 17 '22 at 20:54
  • @Nyerguds You are correct, but the issue here is the code assumes you are on a little endian system (it will probably fail on a big endian one, I didn't check). The meaning of each function, let's say ReadLittleEndianInt16 is not _"I'm going to read a little endian binary data and get the value in memory",_ what they do is _"I'm assuming those datas are big endian, and I'll swap the bytes for a little endian configuration no matter the endianness of the system I'm on"._ – Karl Stephen Apr 17 '22 at 20:58
  • @KarlStephen So? Endianness of the _system_ is completely irrelevant when dealing with _file specs_ that have a specific endianness. Read values from a png header using `BinaryReader` and the result will be corrupted by have its bytes swapped 100% of the time, regardless of the system it's ran on. Reading it on a different-endian system won't magically change the raw bytes in the png file, and since `BinaryReader` is specifically specced to not change its behaviour on different-endian systems, that side won't change either. – Nyerguds Aug 02 '23 at 15:44
5

I did this for PNG file

  var buff = new byte[32];
        using (var d =  File.OpenRead(file))
        {            
            d.Read(buff, 0, 32);
        }
        const int wOff = 16;
        const int hOff = 20;            
        var Widht =BitConverter.ToInt32(new[] {buff[wOff + 3], buff[wOff + 2], buff[wOff + 1], buff[wOff + 0],},0);
        var Height =BitConverter.ToInt32(new[] {buff[hOff + 3], buff[hOff + 2], buff[hOff + 1], buff[hOff + 0],},0);
Danny D
  • 828
  • 1
  • 9
  • 20
1

Yes, you can absolutely do this and the code depends on the file format. I work for an imaging vendor (Atalasoft), and our product provides a GetImageInfo() for every codec that does the minimum to find out dimensions and some other easy to get data.

If you want to roll your own, I suggest starting with wotsit.org, which has detailed specs for pretty much all image formats and you will see how to identify the file and also where information in it can be found.

If you are comfortable working with C, then the free jpeglib can be used to get this information too. I would bet that you can do this with .NET libraries, but I don't know how.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
  • is it safe to assume that using [`new AtalaImage(filepath).Width`](http://www.atalasoft.com/docs/joltimage/docs103/com/atalasoft/imaging/AtalaImage.html#AtalaImage(java.lang.String)) does something similar? – drzaus Jan 20 '14 at 22:25
  • or just [`Atalasoft.Imaging.Codec.RegisteredDecoders.GetImageInfo ( fullPath ) .Size`](https://www.atalasoft.com/cs/forums/thread/13163.aspx) – drzaus Jan 20 '14 at 22:27
  • 1
    The first (AtalaImage) reads the entire image -- the second (GetImageInfo) reads the minimal metadata to get the elements of an image info object. – Lou Franco Jan 22 '14 at 16:16
-2

It's going to depend on the file format. Usually they will state it up in the early bytes of the file. And, usually, a good image-reading implementation will take that into account. I can't point you to one for .NET though.

easeout
  • 8,665
  • 5
  • 43
  • 51