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

+0

Я пробовал это, но последовательность завершилась 0xe1 вместо 0xe0, а кодировка ASCII вышла как EXIF. Я предполагаю, что это другой тип изображения JPEG, но это означает, что это решение не работает для всех изображений JPEG. – Grungondola

+0

@Grungondola Вы правы ... есть целая куча '.jpg' файлов, которые не будут работать с кодом выше. После обширных исследований я могу сказать, что наилучшим способом извлечения метаданных изображения является [imagemagick] (http://www.imagemagick.org/script/binary-releases.php) ... Чтобы обеспечить лучшую изоляцию от процесс хостинга, мы вызываем автономный 'magick.exe ident' с' System.Diagnostics.Process' и анализируем метаданные из основного процесса. Довольно много пуленепробиваемых. – spender

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

Смежные вопросы