【WP 8.1开发】如何处理摄像头翻转的问题
模拟器就像我们儿时的梦境,在其上运行应用程序时,一切总是那么美好的;而真机测试如同我们这个纷乱无章的现实世界,你会遇到各种小人和畜生,常常会遭受莫名的挫折。面对挫折,有人迎难而上,或不予理采,走自己的路;有的人则打退堂鼓。
面对摄像头翻转的问题,有些人也会选择逃避。我为什么不喜欢现在的某些程序员,就是因为这些人只会逃避和制造问题,遇到问题不是去寻找解决方案,而是坐在那里喊爹骂娘。虽然不可能所有问题都可以解决,但是,有许多问题是可以解决的,而这些人总心浮气躁,不愿意静下心来好好思考。
N+6年前我曾经读过一本好书,名叫《方法总比问题多》,捧着这个心念,我认为摄像头翻转的问题是可以解决的。
通常,我们很少会调用前置摄像头,多数情况下用到的是后置摄像头。当然了,解决方法是类似的,因此,为了简单易懂,本文我就以后置摄像头为例,分享一下我的解决方案,如果你有更好的方法,也不妨让大伙儿一起参考参考。
一般而言,真机上的摄像头是与手机横放时的角度一致,即偏了90度(手机逆时针旋转)。


也就是说,当手机逆时针旋转90度后,机器的方向就与摄像头一致了。针对这一情况,我们只要能做到一件事,那就可以解决摄像头翻转的问题了。
锁定页面的方向,即当手机方向改变时,禁止页面跟着旋转就可以了。
此处以Silverlight框架为例,Runtime App比较好办,直接在清单文件中把屏幕方向强制为横向即可。但Silverlight程序就需要一些步骤。
1、设置页面的SupportedOrientations="Landscape",Orientation="LandscapeLeft",如下面XAML所示。
<phone:PhoneApplicationPage
x:Class="AppCamera.MainPage"
……
SupportedOrientations="Landscape" Orientation="LandscapeLeft"
shell:SystemTray.IsVisible="False">
……
这样做就把页面所支持的方向限制为横向,页面的默认方向也改为LandscapeLeft,即手机逆时针旋转90,如果是LandscapeRight,v那就是手机逆时针旋转270度。
2、光是把页面强制为横向还不行,因为横向有两个方向——90度和270度,当手机转动90度后,其方向正好与摄像头吻合,但是,一旦手机旋转270度后,就正好与摄像头的方向相反,即转了180度,这时候,你在手机屏幕上看到的摄像预览是倒过来的,而拍出来的照片当然也是倒立的,关于保存照片的问题,稍后再说。
因此,我们必须想办法,阻止页面更改方向,正好,页面类有一个虚方法叫OnOrientationChanged,当页面的方向发生改变后,会调用该方法。我们只要重写这个方法,并且不要加入任何代码,就能阻止页面基类调用该方法,也就达到了阻止页面改变方向了,“搜狐拍客”就是用这种方法来解决翻转问题的。
protected override void OnOrientationChanged ( OrientationChangedEventArgs e )
{
// 把下面的代码注释掉,页面的方向就会锁定
//base.OnOrientationChanged(e);
}
注意。base.OnOrientationChanged(e);这行代码必须去掉,不然基类会调用。
3、通过上述步骤,是解决了摄像头预览翻转的问题,但又引出另一个新问题:如果屏幕方向与摄像头的方向不一致,那么拍照出来的照片也会反过来的。这个问题就必须在图像文件上做功夫了,也就是把图像的方向调整过来再保存。
我的示例是使用MediaCapture类来拍摄的,拍到的图片是直接保存到文件或流中了,那我们如何修改图片呢?
在Windows.Graphics.Imaging命名空间下,BitmapDecoder类可以用来对图像进行解码,并可以提取图像的像素数据;BitmapEncoder类可以对图像的像素数据进行编码为图像文件。
对,我们就是利用这两个类,先将摄像头拍到的照片解码,然后利用旋转变换来修改图像的方向,最后将修改后的图像重新编码就可以了。至于要把图像向哪个方向旋转,大家不妨自己试一试,对比一下就能知道了。
以下是参考代码:
#region 图像解码与编码
async Task EncodeImage ( IRandomAccessStream inStream, IRandomAccessStream outStream )
{
Guid jpegIDen = BitmapEncoder.JpegEncoderId; //编码器ID
Guid jpegIDde = BitmapDecoder.JpegDecoderId; //获取解码器ID
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(jpegIDde, inStream);
byte[] buffer= ( await decoder.GetPixelDataAsync()).DetachPixelData();
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(jpegIDen, outStream);
// 判断手机方向,以改变图像方向
var ort = ortsensor.GetCurrentOrientation();
switch (ort)
{
case SimpleOrientation.NotRotated:
encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise90Degrees;
break;
case SimpleOrientation.Rotated180DegreesCounterclockwise:
encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise270Degrees;
break;
case SimpleOrientation.Rotated270DegreesCounterclockwise:
encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise180Degrees;
break;
case SimpleOrientation.Rotated90DegreesCounterclockwise:
encoder.BitmapTransform.Rotation = BitmapRotation.None;
break;
}
// 设置像素数据
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, decoder.PixelWidth, decoder.PixelHeight, decoder.DpiX, decoder.DpiY, buffer);
await encoder.FlushAsync();
}
#endregion
由于在确认图像旋转方向前,我们必须知道手机的当前方向。比较简单的方法是直接访问Windows.Graphics.Display.DisplayProperties类的CurrentOrientation属性,不过这个类在新版本中可能会被删除,所以我就不用这个方法。我于是选用了一个稍稍复杂点的方法——使用方向传感器。这种方法有点装逼,不过正好我们可以发挥一下传感器的用处,其实屏幕方向也是通过方向(重力)传感器来识别的。
为了让开发者可以轻松识别出手机的几个特殊方向,以SimpleOrientation枚举定义了几个比较通用的方向。这些值的含义如下表所示。

对应地,在Windows.Devices.Sensors命名空间下,有一个SimpleOrientationSensor类,它表示方向传感器,它可以提供上表所示的几个特殊方向的值的实时报告,这样我们就不用自己来计算坐标值了。
声明SimpleOrientationSensor实例,处理OrientationChanged事件。
if (ortsensor == null)
{
ortsensor = SimpleOrientationSensor.GetDefault();
}
……
ortsensor.OrientationChanged += ortsensor_OrientationChanged; .............. void ortsensor_OrientationChanged ( SimpleOrientationSensor sender, SimpleOrientationSensorOrientationChangedEventArgs args )
{
// 根据方向旋转拍摄图标
var o = args.Orientation;
System.Diagnostics.Debug.WriteLine("方向:{0}", o);
Dispatcher.BeginInvoke(() =>
{
UpdateOrientation(o);
});
}
在上面对图像进行编码的代码中,是通过SimpleOrientationSensor对象的GetCurrentOrientation方法来获取手机当前所处的方向,进而判断出图像应该旋转的方向。
switch (ort)
{
case SimpleOrientation.NotRotated:
encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise90Degrees;
break;
case SimpleOrientation.Rotated180DegreesCounterclockwise:
encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise270Degrees;
break;
case SimpleOrientation.Rotated270DegreesCounterclockwise:
encoder.BitmapTransform.Rotation = BitmapRotation.Clockwise180Degrees;
break;
case SimpleOrientation.Rotated90DegreesCounterclockwise:
encoder.BitmapTransform.Rotation = BitmapRotation.None;
break;
}
好了,经过以上几个步骤,摄像头翻转的问题可以得到解决了。


下面是示例下载地址,和上一篇文章中的示例一样,我只是做了一些修改。
http://files.cnblogs.com/tcjiaan/AppCamera.zip
【WP 8.1开发】如何处理摄像头翻转的问题的更多相关文章
- 【WP 8.1开发】解决摄像头翻转问题(RuntimeApp篇)
昨天,我非常马虎地给大家说了有关处理物理摄像头翻转的话题,今天,还是这个话题,而且内容不差,只是为了完整性,顺便也提供了运行时API的版本,其实实现起来与SL框架版本差不多,毕竟这两个框架都有不少AP ...
- 【WP 8.1开发】How to 图像处理
在今天的吹牛节目开始之前,先交代一件事: 关于玩WP 8.1开发所使用的VS版本问题.对版本的要求是2013的Update2,这是最低要求,只要是这个版本或以上都可以,而update3,update4 ...
- 移动端Web开发如何处理横竖屏
<!Doctype html> <html> <head> <meta charset="utf-8"> <meta id=& ...
- 【WP 8.1开发】解决调用真实摄像头会死机的问题
无论你是用Silverlight还是用RT的API来开发,在使用MediaCapture拍照片或录视频时,要是在模拟器上运行会万事大吉:但是,一旦放到真实手机上运行,肯定有人发现了,细心的朋友肯定发现 ...
- 【WP 8.1开发】推送通知测试服务端程序
所谓推送通知,用老爷爷都能听懂的话说,就是: 1.我的服务器将通知内容发送到微软的通知服务器,再由通知服务器帮我转发消息. 2.那么,微软的推送服务器是如何知道我的服务器要发消息给哪台手机呢?手机客户 ...
- 【WP 8.1开发】电子罗盘
罗盘,估计也不用我过多介绍,学过初中物理的都知道,不管是指南针,还是指北针,其本质就是用来辨别方向的. 操作电子罗盘伟感器也不复杂,主要就是两个角度: 1.当前方向与磁北的夹角: 2.当前方向与地北的 ...
- 【WP 8.1开发】文件选取器的使用方法
在以往的WP7x/8.0开发中,我们使用选择器可以浏览并打开图片.音频.视频等一些特殊文件,在8.0 SDK中的运行时API(从Win 8 app中移植)尽管提供了Windows.Storage.Pi ...
- 【WP 8.1开发】如何把自定义字体塞进应用里
或许,系统自带的字体不足以体现应用程序的魅力,对于表现极强的汉字来说,更是如此.这时候,我们就会想,要是能把网上下载的艺术字体塞到应用包中,那岂不美哉?那么,这可以实现吗?答案是Yes的. 接下来,阿 ...
- 【WP 8.1开发】自定义(RAW)通知的使用
继续前面的话题,还是推送通知.上一篇文章中遗留了RAW通知的推送没有给各位演示,特特地留到现在,不为别的,只为这个RAW通知有点意思,玩起来会比较有意思.官方文档将RAW通知译为“原始通知”,这里还是 ...
随机推荐
- RichTextBox着色与着色不闪
近来写的一个数据查询分析器意外的快捷,不到两晚工夫就搞定了.完成度相当的高.当然少不了关键字着色,不过着色的代码来自的网上,看了一下感觉过多的循环 //文本框改变事件 int index = this ...
- 使用Maven自动部署Tomcat 6和Tomcat 7下Web应用
使用Maven自动部署Tomcat 6和Tomcat 7下Web应用 开启Tomcat远程管理权限 在tomcat的config目录下的tomcat-users.xml文件, <role rol ...
- 第56讲:Scala中Self Types实战详解
今天学习了self type的内容,让我们来看下代码 package scala.learn class Self{ self => val tmp = "Scala" ...
- [原] XAF 如何啟用ListView橫向滾動條
using System; using DevExpress.ExpressApp; using DevExpress.ExpressApp.Win.Editors; using DevExpress ...
- 教你如何快速下载旧版本的Firefox浏览器
http://blog.csdn.net/gh0st007/article/details/18937421 更新后的ff使用过程中经常出现卡顿的现象,之前并没有出现,于是想找老版本的ff安装一下.发 ...
- hdu 5718(Oracle)大数加法
曾经有一位国王,统治着一片未名之地.他膝下有三个女儿. 三个女儿中最年轻漂亮的当属Psyche.她的父亲不确定她未来的命运,于是他来到Delphi神庙求神谕. 神谕可以看作一个不含前导零的正整数n n ...
- JS设计模式初探
目的:设计模式众多,尝试用博客记录下学到的不同设计模式的优劣,方便以后查阅. 前言:半年前看高程的时候看到设计模式这章,云里雾里,不是看不明白,而是不明白为啥要如此麻烦只为创建一个对象.直到最近完成了 ...
- Centos普通用户提权至ROOT
1.利用/bin/ping的漏洞普通用户提权.(rws中的s) [root@localhost ~]# ls -l /bin/ping -rwsr-xr-x. root root 9月 /bin/pi ...
- HTML5-布局的使用
DIV布局: <!DOCTYPE html> <html> <head lang="en"> <meta charset="UT ...
- Mac中使用port升级gcc版本
Mac OS中的gcc版本可能不会满足实际使用要求,需要对其升级. 这里介绍使用port方式来升级gcc版本.Macports是Mac OS中的软件包管理工具. 首先,安装Macports 这里提供O ...