C# 从JPEG解析图像大小

C# 从JPEG解析图像大小,c#,header,jpeg,C#,Header,Jpeg,我想知道是否有一种便宜的方法可以在加载一个字节数组后获得JPEG的宽度和高度 我知道JpegBitmapDecoder可以获得JPEG的像素宽度和高度,但它也加载了大量信息,我认为这将是一个昂贵的操作 有没有其他方法可以从字节数组中获取宽度和高度,而无需对其进行解码 谢谢几年前我读过一篇CodeProject文章: 我不是100%确定它有多好,我自己也没有测试过,但作者肯定对它很满意;他的测试也证明了它比阅读整个图像要快得多,正如你所期望的: 这是文章本身。。希望这是你需要的! 您要查找的代码从

我想知道是否有一种便宜的方法可以在加载一个字节数组后获得JPEG的宽度和高度

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

有没有其他方法可以从字节数组中获取宽度和高度,而无需对其进行解码


谢谢

几年前我读过一篇CodeProject文章: 我不是100%确定它有多好,我自己也没有测试过,但作者肯定对它很满意;他的测试也证明了它比阅读整个图像要快得多,正如你所期望的:

这是文章本身。。希望这是你需要的! 您要查找的代码从这里开始:

UPD:另外,请检查底部的注释。。尤其是最后一个排名靠前的。。可能有助于使其更通用


此外,更深入、更高级的信息可以在这里找到:

几年前,我读过一篇CodeProject文章: 我不是100%确定它有多好,我自己也没有测试过,但作者肯定对它很满意;他的测试也证明了它比阅读整个图像要快得多,正如你所期望的:

这是文章本身。。希望这是你需要的! 您要查找的代码从这里开始:

UPD:另外,请检查底部的注释。。尤其是最后一个排名靠前的。。可能有助于使其更通用


另外,更深入的高级信息可以在这里找到:

不知什么原因,我没有去睡觉,而是去做这个

这里有一些代码可以用最少的存储需求来解决这个问题

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);
    }
}

不知什么原因,我没有去睡觉,而是去做这个

这里有一些代码可以用最少的存储需求来解决这个问题

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);
    }
}

+1我想这就是超越提供答案的意义所在!我尝试了这个方法,但是序列以0xe1而不是0xe0结束,ASCII编码结果为EXIF。我猜这是一种不同类型的JPEG图像,但这意味着该解决方案不适用于所有JPEG图像。@Grungondola你说得对。。。有一大堆.jpg文件不能与上面的代码一起使用。经过广泛的研究,我可以说目前提取图像元数据的最佳方法是使用。。。为了提供与宿主进程的最佳隔离,我们调用独立的magick.exe identified with System.Diagnostics.process并从进程的stdout解析元数据。几乎是防弹的。+1我想这就是超越提供答案的意义所在!我尝试了这个方法,但是序列以0xe1而不是0xe0结束,ASCII编码结果为EXIF。我猜这是一种不同类型的JPEG图像,但这意味着该解决方案不适用于所有JPEG图像。@Grungondola你说得对。。。有一大堆.jpg文件不能与上面的代码一起使用。经过广泛的研究,我可以说目前提取图像元数据的最佳方法是使用。。。为了提供与宿主进程的最佳隔离,我们调用独立的magick.exe identified with System.Diagnostics.process并从进程的stdout解析元数据。几乎是防弹的。