如何获取图像文件的尺寸?

77

我有一个名为FPN = "c:\ggs\ggs Access\images\members\1.jpg "的文件。

我正在尝试获取图像 1.jpg 的尺寸,并且在加载之前我想检查图像尺寸是否有效。


据我所知,没有任何图像格式可以具有0像素的尺寸... - Nyerguds
4个回答

149
System.Drawing.Image img = System.Drawing.Image.FromFile(@"c:\ggs\ggs Access\images\members\1.jpg");
MessageBox.Show("Width: " + img.Width + ", Height: " + img.Height);

1
@User1:你应该编辑你的问题,更清楚地表达“size”的含义。 - Joel Etherton
4
内存不足,它会抛出一个异常。 - user682417
可以将URI用作FromFile()的参数吗? - mko
5
@user682417 考虑使用 Image.FromStream 方法,这样可以避免将整个文件加载到内存中(更快),请参考 https://www.roelvanlisdonk.nl/2012/02/28/fastest-way-to-read-dimensions-from-a-picture-image-file-in-c/。 - drzaus
2
针对 .NET Core NuGet 包 System.Drawing.Common,请参考以下链接:https://www.hanselman.com/blog/HowDoYouUseSystemDrawingInNETCore.aspx。 - sobelito
显示剩余2条评论

50

Wpf类System.Windows.Media.Imaging.BitmapDecoder无法读取整个文件,只能读取元数据。

using(var imageStream = File.OpenRead("file"))
{
    var decoder = BitmapDecoder.Create(imageStream, BitmapCreateOptions.IgnoreColorProfile,
        BitmapCacheOption.Default);
    var height = decoder.Frames[0].PixelHeight;
    var width = decoder.Frames[0].PixelWidth;
}

更新 2019-07-07 处理 exif 格式的图片会稍微复杂一些。由于某些原因,iPhone 保存的图像是旋转的,为了补偿这一点,它们还设置了“在显示之前旋转此图像”exif 标志。

GIF 格式也是相当复杂的。可能没有任何一帧具有完整的 GIF 尺寸,你必须从偏移量和帧大小中聚合它。

所以我使用了 ImageProcessor ,它可以为我解决所有问题。但我从未检查过它是否完全读取了整个文件,因为有些浏览器不支持 exif,我必须另存一个旋转版本。

using (var imageFactory = new ImageFactory())
{
    imageFactory
        .Load(stream)
        .AutoRotate(); //takes care of ex-if
    var height = imageFactory.Image.Height,
    var width = imageFactory.Image.Width
}

这应该是最佳答案,因为它实际上回答了问题。 - person27
@person27 感谢您的评论,我完全忘记了QA在我的代码中添加了一些恶意图像的答案。现在答案已经更新。 - Atomosk
ImageProcessor 网站上没有列出如何使用的说明,Nuget 包页面也没有安装步骤。我有遗漏什么吗? - ΩmegaMan
1
@ΩmegaMan 顶部有3个链接,点击 ImageProcessor 可以访问 https://imageprocessor.org/imageprocessor/imagefactory/#example,而 Getting Started 中有 Install Via Nuget 部分。 - Atomosk

4

针对 .NET Core 用户和任何不想使用第三方库(并且像我一样阅读规范并保持简单性)的人,这里是 JPEG 尺寸的解决方案:

public class JPEGPicture
{
  private byte[] data;
  private ushort m_width;
  private ushort m_height;

  public byte[] Data { get => data; set => data = value; }
  public ushort Width { get => m_width; set => m_width = value; }
  public ushort Height { get => m_height; set => m_height = value; }
    
  public void GetJPEGSize()
  {
    ushort height = 0;
    ushort width = 0;
    for (int nIndex = 0; nIndex < Data.Length; nIndex++)
    {
      if (Data[nIndex] == 0xFF)
      {
        nIndex++;
        if (nIndex < Data.Length)
        {
          /*
              0xFF, 0xC0,             // SOF0 segement
              0x00, 0x11,             // length of segment depends on the number of components
              0x08,                   // bits per pixel
              0x00, 0x95,             // image height
              0x00, 0xE3,             // image width
              0x03,                   // number of components (should be 1 or 3)
              0x01, 0x22, 0x00,       // 0x01=Y component, 0x22=sampling factor, quantization table number
              0x02, 0x11, 0x01,       // 0x02=Cb component, ...
              0x03, 0x11, 0x01        // 0x03=Cr component, ...
          */
          if (Data[nIndex] == 0xC0)
          {
            Console.WriteLine("0xC0 information:"); // Start Of Frame (baseline DCT)
            nIndex+=4;
            if (nIndex < Data.Length-1)
            {
              // 2 bytes for height
              height = BitConverter.ToUInt16(new byte[2] { Data[++nIndex], Data[nIndex-1] }, 0);
              Console.WriteLine("height = " + height);
            }
            nIndex++;
            if (nIndex < Data.Length - 1)
            {
              // 2 bytes for width
              width = BitConverter.ToUInt16(new byte[2] { Data[++nIndex], Data[nIndex-1] }, 0);
              Console.WriteLine("width = " + width);
            }
          }
        }
      }
    }
    if (height != 0)
      Height = height;
    if (width != 0)
      Width = width;
  }

  public byte[] ImageToByteArray(string ImageName)
  {
    FileStream fs = new FileStream(ImageName, FileMode.Open, FileAccess.Read);
    byte[] ba = new byte[fs.Length];
    fs.Read(ba, 0, Convert.ToInt32(fs.Length));
    fs.Close();

    return ba;
   }
 }

class Program
{
  static void Main(string[] args)
  {
    JPEGPicture pic = new JPEGPicture();
    pic.Data = pic.imageToByteArray("C:\\Test.jpg");
    pic.GetJPEGSize();
  }
}
    

我为想要改进渐进DCT代码的人留下了一个空间:

if (Data[nIndex] == 0xC2)

3

很遗憾,System.DrawingImageProcessor仅支持Windows平台,因为它们是GDI(图形设备接口)的简单包装,而GDI是非常古老的Win32(Windows)非托管绘图API。

相反,只需从NuGet安装SixLabors / ImageSharp 库。以下是如何使用它获取大小的方法:

using (var image = SixLabors.ImageSharp.Image.Load("image-path."))
{
    var width = image.Width;
    var height = image.Height;
}

1
似乎他们的许可证要求在商业项目中使用时购买许可证。 - Uwe Keim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接