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
精彩评论