当前位置: 首页 > news >正文

.NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)

获取图片宽高的方法有很多种,本文介绍 .NET 中获取图片宽高的几种方法并评估其性能。如果你打算对大量图片进行一些处理,本文可能有用。


本文内容

    • 本文即将评估的方法
      • `System.Drawing.Imaging.Metafile`
      • `System.Drawing.Bitmap`
      • `System.Windows.Media.Imaging.BitmapImage`
      • `System.Windows.Media.Imaging.BitmapDecoder`
    • 性能对比

本文即将评估的方法

本文即将采用以下四种方法获取图片:

  1. System.Drawing.Imaging.Metafile
  2. System.Drawing.Bitmap
  3. System.Windows.Media.Imaging.BitmapImage
  4. System.Windows.Media.Imaging.BitmapDecoder

System.Drawing.Imaging.Metafile

实际上不要被这个名字误解了,Metafile 并不是“某个图片的元数据”,与之对应的 MetafileHeader 也不是“某个图片的元数据头”。Metafile 是微软 Windows 系统一种图片格式,也就是大家熟悉的 wmf 和 emf,分别是 Windows Metafile 和 Enhanced Metafile。

所以指望直接读取图片元数据头来提升性能的的小伙伴们注意啦,这不是你们要找的方法。

不过为什么这个也能拿出来说,是因为此类也可以读取其他格式的图片。

var header = Metafile.FromFile(@"D:\blog.walterlv.com\large-background-image.jpg");
var witdh = header.Width;
var height = header.Height;

能拿到。

System.Drawing.Bitmap

这个实际上是封装的 GDI+ 位图,所以其性能最好也是 GDI+ 的性能,然而都知道 GDI+ 的静态图片性能不错,但比起现代的其他框架来说确实差得多。

var bitmap = new Bitmap(@"D:\blog.walterlv.com\large-background-image.jpg");
var witdh = bitmap.Width;
var height = bitmap.Height;

System.Windows.Media.Imaging.BitmapImage

这是 WPF 框架中提供的显示位图的方法,生成的图片可以直接被 WPF 框架显示。

var bitmap = new BitmapImage(new Uri(@"D:\blog.walterlv.com\large-background-image.jpg", UriKind.Absolute));
var witdh = bitmap.Width;
var height = bitmap.Height;

System.Windows.Media.Imaging.BitmapDecoder

这也是 WPF 框架中提供的方法,但相比完全加载图片到可以显示的 System.Windows.Media.Imaging.BitmapImage,此方法的性能会好得多。

var decoder = new JpegBitmapDecoder(new Uri(@"D:\blog.walterlv.com\large-background-image.jpg", UriKind.Absolute), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand);
var frame = decoder.Frames[0];
var witdh = frame.PixelWidth;
var height = frame.PixelHeight;

性能对比

为了测试性能,我使用下面这张非常大的图,同一张图运行多次:

在这里插入图片描述

分别运行以上四个方法各 1 次:

运行 1 次的时间消耗

分别运行以上四个方法各 10 次:

运行 10 次的时间消耗

分别运行以上四个方法各 100 次(可以发现大量的 GC):

运行 100 次的时间消耗

现在,使用不同的图片运行多次。

分别运行以上四个方法各 10 张图片:

运行 10 次的时间消耗

分别运行以上四个方法各 100 张图片(可以发现大量的 GC):

运行 100 次的时间消耗

做成图表,对于同一张图片运行不同次数:

消耗时间(ms)MetafileBitmapBitmapImageBitmapDecoder
1次175107712
10次104110466317
100次103351036056122

同一张图运行不同次数

对于不同图片运行不同次数:

消耗时间(ms)MetafileBitmapBitmapImageBitmapDecoder
1次175107712
10次9989808320
100次1058210617255204
1000次12702312862734564015

不同图片运行不同次数

可以发现,对于 .NET 框架中原生自带的获取图片尺寸的方法来说:

  1. System.Windows.Media.Imaging.BitmapDecoder 的整体性能是最好的
  2. 对于同一张图,System.Windows.Media.Imaging.BitmapImage 的运行时间不随次数的增加而增加,其内部有缓存

参考资料

  • WMF - 维基百科,自由的百科全书

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • 用命令行执行 .NET 单元测试时,如何仅执行符合某些条件的单元测试
  • WPF 中如何绑定附加属性?XAML 中记得加括号,C# 中记得不能用字符串
  • VSCode:当匹配到结果时,如何一次性全部选中操作(复制 删除)?
  • Unity3D 入门:安装 Unity3D 并配置与 Visual Studio 的协作开发环境
  • 在 Visual Studio 2019 (16.5) 中查看托管线程正在等待的锁被哪个线程占用
  • 将 Windows Terminal 作为外部工具集成到其他工具 程序 代码中
  • Unity3D 入门:在 Visual Studio 里使用 Visual Studio Tools for Unity 全套工具
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • Unity3D 入门:为 Unity 的 C# 项目添加 dll 引用或安装 NuGet 包
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • 如何在终端和 PowerShell 中将一个命令自动重复执行多次
  • WPF:无法对元素“XXX”设置 Name 特性值“YYY”。“XXX”在元素“ZZZ”的范围内,在另一范围内定义它时,已注册了名称。
  • 一点点从坑里爬出来:如何正确打开 WPF 里的 Popup?
  • Windows Linux 系统中获取端口被哪个应用程序占用
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • 10个最佳ES6特性 ES7与ES8的特性
  • Android 架构优化~MVP 架构改造
  • Codepen 每日精选(2018-3-25)
  • CSS盒模型深入
  • HTML中设置input等文本框为不可操作
  • LeetCode18.四数之和 JavaScript
  • 分享几个不错的工具
  • 服务器之间,相同帐号,实现免密钥登录
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 今年的LC3大会没了?
  • 世界上最简单的无等待算法(getAndIncrement)
  • RDS-Mysql 物理备份恢复到本地数据库上
  • zabbix3.2监控linux磁盘IO
  • 容器镜像
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • #laravel 通过手动安装依赖PHPExcel#
  • #QT(串口助手-界面)
  • $NOIp2018$劝退记
  • (4)STL算法之比较
  • (k8s中)docker netty OOM问题记录
  • (SpringBoot)第二章:Spring创建和使用
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • .NET CF命令行调试器MDbg入门(三) 进程控制
  • .Net下的签名与混淆
  • .NET与 java通用的3DES加密解密方法
  • .php结尾的域名,【php】php正则截取url中域名后的内容
  • .skip() 和 .only() 的使用
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • @开发者,一文搞懂什么是 C# 计时器!
  • [AIGC] Kong:一个强大的 API 网关和服务平台
  • [CISCN2019 华东北赛区]Web2
  • [HITCON 2017]SSRFme perl语言的 GET open file 造成rce
  • [IE技巧] IE8中HTTP连接数目的变化
  • [J2ME]如何替换Google Map静态地图自带的Marker