Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

get dimensions of an image on the web - avoid memory hog?

Tags:

c#

asp.net

Im getting some images from a webpage at a specified url, i want to get their heights and widths. I'm using something like this:

 Stream str = null;
 HttpWebRequest wReq = (HttpWebRequest)WebRequest.Create(ImageUrl);
 HttpWebResponse wRes = (HttpWebResponse)(wReq).GetResponse();
 str = wRes.GetResponseStream();

 var imageOrig = System.Drawing.Image.FromStream(str);
 int height = imageOrig.Height;
 int width = imageOrig.Width;

My main concern with this is that that the image file may actually be very large,

Is there anything I can do? ie specify to only get images if they are less than 1mb? or is there a better alternative approach to getting the dimension of an image from a webpage?

thanks

like image 653
raklos Avatar asked Jan 21 '23 19:01

raklos


2 Answers

Some (all?) image formats include the width and height property in the header of the file. You could just request enough bytes to be able to read the header and then parse them yourself. You can add a range header to your web request that will request only the first 50 bytes (50 is just an example, you'd probably need less) of the image file with:

wReq.AddRange(0, 50);

I suppose this will only work if you know that the formats you are working with include this data.

Edit: Looks like I misunderstood the AddRange method before. It's fixed now. I also went ahead and tested it out by getting the width and height of a png using this documentation.

static void Main(string[] args)
{
    string imageUrl = "http://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";
    byte[] pngSignature = new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 };
    HttpWebRequest wReq = (HttpWebRequest)WebRequest.Create(imageUrl);
    wReq.AddRange(0, 30);
    WebResponse wRes = wReq.GetResponse();
    byte[] buffer = new byte[30];
    int width = 0;
    int height = 0;

    using (Stream stream = wRes.GetResponseStream())
    {
        stream.Read(buffer, 0, 30);
    }

    // Check for Png
    // 8 byte - Signature
    // 4 byte - Chunk length
    // 4 byte - Chunk type - IDHR (Image Header)
    // 4 byte - Width
    // 4 byte - Height
    // Other stuff we don't care about
    if (buffer.Take(8).SequenceEqual(pngSignature))
    {
        var idhr = buffer.Skip(12);
        width = BitConverter.ToInt32(idhr.Skip(4).Take(4).Reverse().ToArray(), 0);
        height = BitConverter.ToInt32(idhr.Skip(8).Take(4).Reverse().ToArray(), 0);
    }
    // Check for Jpg
    //else if (buffer.Take(?).SequenceEqual(jpgSignature))
    //{
    //    // Do Jpg stuff
    //}
    // Check for Gif
    //else if (etc...

    Console.WriteLine("Width: " + width);
    Console.WriteLine("Height: " + height);
    Console.ReadKey();
}
like image 98
Chris Avatar answered Jan 29 '23 13:01

Chris


You only need to download the header from a graphics file in order to find the picture size, see...

BMP: (only 26 bytes needed) http://www.fileformat.info/format/bmp/corion.htm

JPG: (scan for "Star of Frame" marker) http://wiki.tcl.tk/757

GIF: (10 bytes needed, i.e. first two words of Logical Screen Descriptor) http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp

also, notice how you can read the first couple of bytes to find out what the file-type really is (don't rely on the extension of the filename. For example, a bmp could be named ".gif" by accident. Once you know the filetype you look at the spec to know what offset to read.

P.S. get yourself a hex editor, such as "Hex Editor XVI32", to see the file structure. You can download XVI32 here: http://www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm

like image 22
Someone Somewhere Avatar answered Jan 29 '23 12:01

Someone Somewhere