2010-11-03 73 views
1

我想知道在加载字节数组后,是否有廉价的方式来获取JPEG的宽度和高度。从JPEG解析图像大小

我知道JpegBitmapDecoder可以获得JPEG的像素宽度和高度,但它也加载了很多信息,我认为这会是一个昂贵的操作。

是否有另一种方法从字节数组中获取宽度和高度而不解码?

感谢

回答

14

对于一些未知的原因,而不是去睡觉,我去了这方面的工作。

下面是一些代码,以最小的存储需求解决这个问题。

void Main() 
{ 
    var [email protected]"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); 
    } 
} 
+1

+1我想这就意味着要超越并提供一个答案! – BrokenGlass 2010-11-04 01:34:34

+0

我试过了,但是序列以0xe1而不是0xe0结尾,并且ASCII编码以EXIF形式出现。我猜这是一种不同类型的JPEG图像,但这意味着此解决方案不适用于所有JPEG图像。 – Grungondola 2016-05-18 14:43:35

+0

@Grungondola你是对的......有一大堆'.jpg'文件不适用于上面的代码。经过广泛的研究,我可以说到目前为止提取图像元数据的最好方法是使用[imagemagick](http://www.imagemagick.org/script/binary-releases.php)...为了提供最好的隔离在托管过程中,我们用'System.Diagnostics.Process'调用独立的'magick.exe标识'并从流程的标准输出解析元数据。非常防弹。 – spender 2016-05-18 22:14:36

2

我已经阅读了CodeProject上的文章一对夫妇几年前:) 我不是100%肯定它是多么的好,没有测试它自己,但笔者的绝对幸福用它;还有他的测试证明它比阅读整个图像更快,正如你所期望的那样:)

这里是文章本身..希望这是你需要的! http://www.codeproject.com/KB/cs/ReadingImageHeaders.aspx
的一段代码,你要寻找的开始约在这里:
http://www.codeproject.com/KB/cs/ReadingImageHeaders.aspx#premain3

UPD:同时,检查意见的底部。特别是最后一个(顶部)一个有..可能是有用的使其更通用

而且,更深入,先进的信息可以在这里捡到:http://www.codeproject.com/KB/graphics/iptc.aspx