2010-11-03 95 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