计算照片的面积(WPF篇)
昨天,老周突发其想地给大伙伴们说了一下UWP应用中计算照片面积的玩法,而且老周也表示会提供WPF版本的示例。所以,今天就给大伙们补上吧。
WPF是集成在.net框架中,属于.net的一部分,千万不要跟我说你学.net不学WPF,那是不对的,包括ASP.NET、WCF、WF等都是.net框架的一部分,它们在本质上并没有脱离.net。
废话少扯,扯了也没人听,咱们说正题吧。
WPF库中与UWP的不太一样,图像解码编码API似乎不像UWP中那么强大,大概是因为桌面程序可以调用Win32 API和COM的原因吧。不过,老周必须告诉你一个事,经过测试,用WPF的方法计算照片面积,在性能上远远超过GDI的方式,尤其是对大型照片更是如此。在WPF出现前,在System.Drawing命名空间下有个Iamge类,也派生出了一个Bitmap类,这些类都可以用来计算照片面积。老周在N年前做过一个照片面积计算器,除了计算面积外,还可以输入单价(每平方米多少钱),然后计算冲印照片的面积和最终的价格,并具有简单的票据打印功能。这个程序是基于GDI,即用System.Drawing命名空间下的东东搞的,因为那个时代,WPF还没有问世。
WPF把图像的解码/编码类都内置到UI相关的媒体功能中,就是位于System.Windows.Media.Imaging命名空间下,里面有个BitmapImage类,它可以读到照片的像素宽高,以及分辨率,有了这些参数就可以计算面积了。
但是,你必须注意WPF的线程安全模型是相对严格的,为了保护UI线程不被无意破坏,BitmapImage类是间接继承DispatcherObject类,凡是有Dispatcher的对象,你得明白,它是不能跨线程操作的。如果你要在UI上显示它们,那么位图对象的实例必须属于UI线程。

如果你使用数据绑定时担心性能受影响,可以开启异步绑定,WPF的Binding有个IsAsync属性,开启它,UI线程在调度时会使用辅助线程来加载数据。实验表明,你的CPU核数越多,处理起来越快,到底还是要看配置啊。尤其是处理多媒体,像视频这些,你不能拿一台50年前的电脑来谈性能优化,你应该至少拿一台跟得上时代的电脑来评估。你总不能用春秋战国时期的社会生产力来跟大唐盛世比。
在使用图像时,为了节省开销,你可以设置DecodePixelWidth或DecodePixelHeight
属性,这两个属性不要同时设置,你设置其中一个就行了,这样图像在呈现时可以自动计算比例,不然会使图像变形,当然了,如果你希望图像变形,那就另当别论了。
设置这两个属性,并不影响我们读取图像的真实像素,要获取图像宽高,应访问PixelWidth和PixelHeight属性,DecodePixelHeight/Width不会影响这两个属性的值。另外,通过DpiX和DpiY属性就能得到水平和垂直方向上的分辨率。
好,同样地,还是先封装一个数据类。
public class PhotoData : INotifyPropertyChanged
{
#region 私有字段
int width = default(int), height = default(int);
double dpix = default(double), dpiy = default(double);
BitmapImage bitmap = null;
double area;
#endregion #region INotifyPropertyChanged成员
public event PropertyChangedEventHandler PropertyChanged;
#endregion #region 构造函数
public PhotoData(string filePath)
{
// 实例化图像对象
PhotoImage = new BitmapImage();
PhotoImage.DecodePixelWidth = ;
// 初始化图像
PhotoImage.BeginInit();
PhotoImage.UriSource = new Uri(filePath);
PhotoImage.EndInit(); // 获取需要的参数
Width = PhotoImage.PixelWidth;
Height = PhotoImage.PixelHeight;
DpiX = PhotoImage.DpiX;
DpiY = PhotoImage.DpiY;
// 计算面积
ComputeArea();
}
#endregion #region 方法
private void OnPropertyChanged([CallerMemberName]string prpname = "")
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prpname));
} /// <summary>
/// 计算面积
/// </summary>
private void ComputeArea()
{
// 先将宽度和高度转为英寸
double inchW = Width / DpiX;
double inchH = Height / DpiY;
/*
面积单位为平方米
1英寸 = 2.54厘米
*/
Area = (inchW * 2.54d) * (inchH * 2.54d) / 10000d;
}
#endregion #region 属性
/// <summary>
/// 照片宽度
/// </summary>
public int Width
{
get { return width; }
private set
{
if (value != width)
{
width = value;
OnPropertyChanged();
}
}
} /// <summary>
/// 照片高度
/// </summary>
public int Height
{
get { return height; }
private set
{
if (value != height)
{
height = value;
OnPropertyChanged();
}
}
} /// <summary>
/// 水平分辨率
/// </summary>
public double DpiX
{
get { return dpix; }
private set
{
if (dpix != value)
{
dpix = value;
OnPropertyChanged();
}
}
} /// <summary>
/// 垂直分辨率
/// </summary>
public double DpiY
{
get { return dpiy; }
private set
{
if (value != dpiy)
{
dpiy = value;
OnPropertyChanged();
}
}
} /// <summary>
/// 图像实例
/// </summary>
public BitmapImage PhotoImage
{
get { return bitmap; }
private set
{
if (bitmap != value)
{
bitmap = value;
OnPropertyChanged();
}
}
} /// <summary>
/// 面积(平方米)
/// </summary>
public double Area
{
get { return area; }
private set
{
if (value != area)
{
area = value;
OnPropertyChanged();
}
}
}
#endregion
}
这个我不多解释了,应该比昨天那个更好懂。注意我今天用的单位是平方米,计算平方厘米后,要除以10000。
类似的方法,我们先计算单个照片的面积,并放入到一个集合中。
string[] files = openFileDlg.FileNames;
// 开始计算
photolist.Clear();
isRunning = true;
foreach (string f in files)
{
try
{
PhotoData data = new PhotoData(f);
photolist.Add(data);
}
catch (Exception ex)
{
// 记录异常信息
Trace.WriteLine($"{DateTime.Now.ToLongTimeString()} -- {ex.Message}");
continue;
}
}
然后,统计总面积。
double totalArea = photolist.Sum(d =>
{
if (double.IsInfinity(d.Area))
{
return 0d;
}
return d.Area;
});
为了使这个程序更加生动可爱,更具有内涵,老周还使用了语音朗读API,在System.Speech.Synthesis命名空间下。
// 语音朗读
Task.Run(() =>
{
using (SpeechSynthesizer symthedizer = new SpeechSynthesizer())
{
symthedizer.Speak(msg);
}
});
使用Task来异读朗读,不影响UI上呈现内容。
最后结果请看下图。

好了,该开饭了,今天的牛皮就吹到这里,有空继续吹。
计算照片的面积(WPF篇)的更多相关文章
- 计算照片的面积(UWP篇)
今天先说UWP应用程序上计算照片面积的方法,改天有空,再说说WPF篇. 其实计算照片面积的原理真TMD简单,只要你有本事读到照片的像素高度和宽度,以及水平/垂直方向上的分辨率(DPI)就可以了.计算方 ...
- 工欲善其事,必先利其器 之 WPF篇: 随着开发轨迹来看高效WPF开发的工具和技巧
之前一篇<工欲善其事,必先利其器.VS2013全攻略(安装,技巧,快捷键,插件)!> 看到很多朋友回复和支持,非常感谢,尤其是一些拍砖的喷油,感谢你们的批评,受益良多. 我第一份工作便是W ...
- Java学习之路----计算圆形的面积和周长
题目:计算圆形的面积,其中圆形的半径是随意指定. 源代码以及所有的分析思路都如下: import java.util.Scanner; //引入Scanner类 public class TestAr ...
- Java计算几何图形的面积
对于每个几何图形而言,都有一些共同的属性,如名字.面积等,而其计算面积的方法却各不相同.为了简化开发,请编写程序,定义一个超类来实现输入名字的方法,并使用抽象方法来计算面积. 思路分析: 所谓超类就是 ...
- 【改革春风吹满地 HDU - 2036 】【计算几何-----利用叉积计算多边形的面积】
利用叉积计算多边形的面积 我们都知道计算三角形的面积时可以用两个邻边对应向量积(叉积)的绝对值的一半表示,那么同样,对于多边形,我们可以以多边形上的一个点为源点,作过该点并且过多边形其他点中的某一个的 ...
- DevExpress v18.1新版亮点——WPF篇(五)
用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress WPF v18.1 的新功能,快来下载试用新版本!点击下载& ...
- DevExpress v18.1新版亮点——WPF篇(二)
用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress WPF v18.1 的新功能,快来下载试用新版本!点击下载& ...
- 用java编写一个函数,用于计算桌子的面积,可计算任意边长的桌子
/* *桌子实体类,有属性和方法 */public class Table { String name; // 声明桌子名称 Double width; // 声明桌子宽度 Doub ...
- Java入门:基础算法之计算园的面积
本部分内容介绍如何使用Java计算圆的周长和面积.分两种方法来实现: 1)圆的半径由用户输入 2)圆的半径由程序指定 代码1: /** * @作者: 理工云课堂 * @描述: 用户输入圆的半径,程序结 ...
随机推荐
- 踩石行动:ViewPager无限轮播的坑
2016-6-19 前言 View轮播效果在app中很常见,一想到左右滑动的效果就很容易想到使用ViewPager来实现.对于像我们常说的banner这样的效果,具备无限滑动的功能是可以用ViewPa ...
- 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文
阅读目录 前言 明确业务细节 建模 实现 结语 一.前言 上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/D ...
- Android混合开发之WebViewJavascriptBridge实现JS与java安全交互
前言: 为了加快开发效率,目前公司一些功能使用H5开发,这里难免会用到Js与Java函数互相调用的问题,这个Android是提供了原生支持的,不过存在安全隐患,今天我们来学习一种安全方式来满足Js与j ...
- 启用 Open vSwitch - 每天5分钟玩转 OpenStack(127)
Linux Bridge 和 Open vSwitch 是目前 OpenStack 中使用最广泛的两种虚机交换机技术. 前面各章节我们已经学习了如何用 Linux Bridge 作为 ML2 mech ...
- nodejs项目mysql使用sequelize支持存储emoji
nodejs项目mysql使用sequelize支持存储emoji 本篇主要记录nodejs项目阿里云mysql如何支持存储emoji表情. 因由 最近项目遇到用户在文本输入emoji进行存储的时候导 ...
- 多线程 异步 beginInvoke EndInvoke 使用
有许多耗时操作时,还要响应用户操作.这时候就需要用其他线程或者异步来搞.本来是改造公司的日志组件.因为多上了个国外大区的业务到来本系统来.这个系统其他地方都好就是日志,动不动就要死给我们看.有时候寻找 ...
- python 数据类型 --- 集合
1. 注意列表和集合的区别 set 列表表现形式: list_1 = [1,3,4]; 集合表现形式:set_1= set() list_1 = [1,2,3,4,23,4,2] print(lis ...
- 如何为你的微信小程序体积瘦身?
众所周知,微信小程序在发布的时候,对提交的代码有1M大小的限制!所以,如果你正在写一个功能稍微复杂一点的小程序,就必须得时刻小心注意你的代码是不是快触及这个底线了. 在设计一个小程序之初,我们就需要重 ...
- Android菜单项内容大全
一.介绍: 菜单是许多应用中常见的用户界面组件. Android3.0版本以前,Android设备会提供一个专用"菜单"按钮呈现常用的一些用户操作, Android3.0版本以后, ...
- 【iOS10 SpeechRecognition】语音识别 现说现译的最佳实践
首先想强调一下“语音识别”四个字字面意义上的需求:用户说话然后马上把用户说的话转成文字显示!,这才是开发者真正需要的功能. 做需求之前其实是先谷歌百度一下看有没有造好的轮子直接用,结果真的很呵呵,都是 ...