开发者

Parse image size from JPEG

开发者 https://www.devze.com 2023-01-23 04:23 出处:网络
I was wondering if there was an inexpensive way to get the width and height o开发者_高级运维f a JPEG after loading an array of bytes.

I was wondering if there was an inexpensive way to get the width and height o开发者_高级运维f a JPEG after loading an array of bytes.

I know JpegBitmapDecoder can get the JPEG's pixel width and height but it loads alot of information as well, which I assume would be an expensive operation.

Is there another way to get the width and height from the array of bytes without decoding it?

Thanks


For some unknown reason, instead of going to bed, I went to work on this.

Here's some code that solves this with minimal storage requirements.

void Main()
{
    var filePath=@"path\to\my.jpg";
    var bytes=File.ReadAllBytes(filePath);
    var dimensions=GetJpegDimensions(bytes);
    //or
    //var dimensions=GetJpegDimensions(filePath);
    Console.WriteLine(dimensions);
}
public static Dimensions GetJpegDimensions(byte[] bytes)
{
    using(var ms=new MemoryStream(bytes))
    {
        return GetJpegDimensions(ms);
    }
}
public static Dimensions GetJpegDimensions(string filePath)
{
    using(var fs=File.OpenRead(filePath))
    {
        return GetJpegDimensions(fs);
    }
}
public static Dimensions GetJpegDimensions(Stream fs)
{
    if(!fs.CanSeek) throw new ArgumentException("Stream must be seekable");
    long blockStart;
    var buf = new byte[4];
    fs.Read(buf, 0, 4);
    if(buf.SequenceEqual(new byte[]{0xff, 0xd8, 0xff, 0xe0}))
    {
        blockStart = fs.Position;
        fs.Read(buf, 0, 2);
        var blockLength = ((buf[0] << 8) + buf[1]);
        fs.Read(buf, 0, 4);
        if(Encoding.ASCII.GetString(buf, 0, 4) == "JFIF" 
            && fs.ReadByte() == 0)
        {
            blockStart += blockLength;
            while(blockStart < fs.Length)
            {
                fs.Position = blockStart;
                fs.Read(buf, 0, 4);
                blockLength = ((buf[2] << 8) + buf[3]);
                if(blockLength >= 7 && buf[0] == 0xff && buf[1] == 0xc0)
                {
                    fs.Position += 1;
                    fs.Read(buf, 0, 4);
                    var height = (buf[0] << 8) + buf[1];
                    var width = (buf[2] << 8) + buf[3];
                    return new Dimensions(width, height);
                }
                blockStart += blockLength + 2;
            }
        }
    }
    return null;
}

public class Dimensions
{
    private readonly int width;
    private readonly int height;
    public Dimensions(int width, int height)
    {
        this.width = width;
        this.height = height;
    }
    public int Width
    {
        get{return width;}
    }
    public int Height
    {
        get{return height;}
    }
    public override string ToString()
    {
        return string.Format("width:{0}, height:{1}", Width, Height);
    }
}


I've read a CodeProject article about it a couple years back :) I'm not 100% sure how good it is, and haven't tested it myself, but the author's definitely happy with it; also his tests prove it's a LOT faster than reading the whole image, as you'd expect :)

Here's the article itself.. Hope it's what you need! http://www.codeproject.com/KB/cs/ReadingImageHeaders.aspx
The piece of code you're looking for starts about here:
http://www.codeproject.com/KB/cs/ReadingImageHeaders.aspx#premain3

UPD: Also, check the comments in the bottom.. Especially the last (top) one there.. Might be useful to make it more generic

Also, more in-depth, advanced info can be picked up here: http://www.codeproject.com/KB/graphics/iptc.aspx

0

精彩评论

暂无评论...
验证码 换一张
取 消