• Windows Phone 拍照照片方向不对的问题


    清明小长假完全的在睡梦中度过,看看了两部迅雷下载的电影,稍微搞了搞假前没搞完的应用。节后第一天啥也不相干,不想看书,不想写代码,懒惰之极啊。于是想到开发最近这个应用的时候,遇到的一个问题,网上查了资料,总结了一下,以下是从老外那个文章中总结来的,并非原创。

    使用CameraCaptureTask调用相机拍照的时候,wp会有一个奇怪的现象,那就是不管你拍照的时候你的手机是“portrait”还是“landscape”,它都自认为你使用了“landscape”,所以拍出来的照片,当你使用Image预览的时候,就会感觉方向不对。

     

    手机有四种旋转方向,拍出来的照片的方向都不一样啊,下面借一张另一个老外的图,大家好好看看。


    解释一下啊。

    第一栏就是你的应用的方向,这个和拍照没什么关系。

    第二栏是你拍照时候手机拿的方向,到底怎么拿的你看看你手机就知道了。

    第三栏是拍照后照片在你应用中的现实方向。

    第四栏是需要调整的角度。

    看了以上大家应该明白了,至于你信不信,反正我是信了。

     

    以上是铺垫,下面开始讲解怎么修正以上的问题。

     

    要修正方向不对的问题,就需要知道拍照后照片的方向。要知道照片的方向,就要使用到另一个老外的一个类库ExifLib.这个类库大家一看就知道是获取图片的exif信息的。那个老外开放了源代码,有兴趣大家可以去下载看看。使用这个类库就可以获得拍照的照片的一些信息,当然要包含方向信息了。

    使用CameraCaptureTask之后,Complete之后返回的e.ChosePhoto是一个Stream,由于ExifLib中没有直接操作Stream的方法,所以还需要您劳驾加一个直接操作Stream的方法,方法如下:

    1: public static JpegInfo ReadJpeg(Stream FileStream, string FileName)

       2: {

       3:     DateTime now = DateTime.Now;

       4:     ExifReader reader = new ExifReader(FileStream);

       5:     reader.info.FileSize = (int)FileStream.Length;

       6:     reader.info.FileName = string.Format("{0}.jpg", FileName);

       7:     reader.info.LoadTime = (TimeSpan)(DateTime.Now - now);

       8:     return reader.info;

       9: }

    最后,提供给你的代码中的新的ExifLib已经加了这个方法了,所以也可以直接使用那个库。

     

    这个库改完之后,就要进入纠正方向的正题了。

    纠正方向还有两种方法,其实也是两种不同的需求。

    1、如果只是为了预览照片,完全可以使用Image的那个RenderTransform属性修改旋转度,代码应该是这样的吧:

    1: <Image Margin="8,8,8,159" x:Name="ChosenPicture" RenderTransformOrigin="0.5,0.5">

       2:     <Image.RenderTransform>

       3:         <RotateTransform x:Name="ImageRotate" />

       4:     </Image.RenderTransform>

       5: </Image>

    然后在后台中判断照片的需要旋转度。后台代码如下:

    void OnCameraCaptureCompleted(object sender, PhotoResult e)

       2: {

       3:     capturedImage = e.ChosenPhoto;

       4: 

       5:     BitmapImage bmp = new BitmapImage();

       6:     bmp.SetSource(e.ChosenPhoto);

       7: 

       8:     ChosenPicture.Source = bmp;

       9: 

      10:     // figure out the orientation from EXIF data

      11:     e.ChosenPhoto.Position = 0;

      12:     JpegInfo info = ExifReader.ReadJpeg(e.ChosenPhoto, e.OriginalFileName);

      13:

      14: 

      15:     switch (info.Orientation)

      16:     {

      17:         case ExifOrientation.TopLeft:

      18:         case ExifOrientation.Undefined:

      19:             ImageRotate.Angle = 0d;

      20:             break;

      21:         case ExifOrientation.TopRight:

      22:             ImageRotate.Angle = 90d;

      23:             break;

      24:         case ExifOrientation.BottomRight:

      25:             ImageRotate.Angle = 180d;

      26:             break;

      27:         case ExifOrientation.BottomLeft:

      28:             ImageRotate.Angle = 270d;

      29:             break;

      30:     }

      31: }

    这段代码大家可以结合着上面那个有四个栏的图看,就好理解了。这样操作之后,预览的时候,正常方向拿手机的时候,照片就都是正方向的了。

     

    但是上面的解决方案只能够解决预览的时候方向不对的问题,如果你想把照片保存起来,最后保存的照片的方向还是不对,所以以上方案只是治标并没有治本,那下面就讨论一下治本的方案。

    如果要治本,那就要重新构造图片,怎么重新构造呢,看下面的代码吧,我也懒的写太多了,大家好好看看吧,有些代码真真是没看懂,有懂的可以给解释一下。

    void OnCameraCaptureCompleted(object sender, PhotoResult e)

       2: {

       3:     // figure out the orientation from EXIF data

       4:     e.ChosenPhoto.Position = 0;

       5:     JpegInfo info = ExifReader.ReadJpeg(e.ChosenPhoto, e.OriginalFileName);

       6: 

       7:     _width = info.Width;

       8:     _height = info.Height;

       9:     _orientation = info.Orientation;

      10: 

      11:     PostedUri.Text = info.Orientation.ToString();

      12: 

      13:     switch (info.Orientation)

      14:     {

      15:         case ExifOrientation.TopLeft:

      16:         case ExifOrientation.Undefined:

      17:             _angle = 0;

      18:             break;

      19:         case ExifOrientation.TopRight:

      20:             _angle = 90;

      21:             break;

      22:         case ExifOrientation.BottomRight:

      23:             _angle = 180;

      24:             break;

      25:         case ExifOrientation.BottomLeft:

      26:             _angle = 270;

      27:             break;

      28:     }

      29: 

      30:     if (_angle > 0d)

      31:     {

      32:         capturedImage = RotateStream(e.ChosenPhoto, _angle);

      33:     }

      34:     else

      35:     {

      36:         capturedImage = e.ChosenPhoto;

      37:     }

      38: 

      39:     BitmapImage bmp = new BitmapImage();

      40:     bmp.SetSource(capturedImage);

      41: 

      42:     ChosenPicture.Source = bmp;          

      43: }

      44: 

      45: private Stream RotateStream(Stream stream, int angle)

      46: {

      47:     stream.Position = 0;

      48:     if (angle % 90 != 0 || angle < 0) throw new ArgumentException();

      49:     if (angle % 360 == 0) return stream;

      50: 

      51:     BitmapImage bitmap = new BitmapImage();

      52:     bitmap.SetSource(stream);

      53:     WriteableBitmap wbSource = new WriteableBitmap(bitmap);

      54: 

      55:     WriteableBitmap wbTarget = null;

      56:     if (angle % 180 == 0)

      57:     {

      58:         wbTarget = new WriteableBitmap(wbSource.PixelWidth, wbSource.PixelHeight);

      59:     }

      60:     else

      61:     {

      62:         wbTarget = new WriteableBitmap(wbSource.PixelHeight, wbSource.PixelWidth);

      63:     }

      64:  // 循环体内的代码真真的没看懂啊,有懂的可以解释一下啊。

      65:     for (int x = 0; x < wbSource.PixelWidth; x++)

      66:     {

      67:         for (int y = 0; y < wbSource.PixelHeight; y++)

      68:         {

      69:             switch (angle % 360)

      70:             {

      71:                 case 90:

      72:                     wbTarget.Pixels[(wbSource.PixelHeight - y - 1) + x * wbTarget.PixelWidth] = wbSource.Pixels[x + y * wbSource.PixelWidth];

      73:                     break;

      74:                 case 180:

      75:                     wbTarget.Pixels[(wbSource.PixelWidth - x - 1) + (wbSource.PixelHeight - y - 1) * wbSource.PixelWidth] = wbSource.Pixels[x + y * wbSource.PixelWidth];

      76:                     break;

      77:                 case 270:

      78:                     wbTarget.Pixels[y + (wbSource.PixelWidth - x - 1) * wbTarget.PixelWidth] = wbSource.Pixels[x + y * wbSource.PixelWidth];

      79:                     break;

      80:             }

      81:         }

      82:     }

      83:     MemoryStream targetStream = new MemoryStream();

      84:     wbTarget.SaveJpeg(targetStream, wbTarget.PixelWidth, wbTarget.PixelHeight, 0, 100);

      85:     return targetStream;

      86: }

    这就是重新构造一个正确方向的图片的方法,以上代码是直接从老外的文章中贴过来的,文章最后,我会提供我精炼出的代码,大家可以直接拿过去用。

     

    好了,就写这么多吧,文笔太差,大家尽量看吧,看不懂,可以一起讨论一下。哈哈。

     

    以下提供我总结的以上方法的代码,放在一个实例应用中了,大家可以根据需要修改或者不修改使用,哈哈。

    实例代码下载》》》 

     参考文章:

    Handling picture orientation in CameraCaptureTask in Windows Phone 7

    http://www.mindscapehq.com/blog/index.php/2012/02/28/windows-phone-7-working-with-camera-tasks/ 

  • 相关阅读:
    捕获mssqlservice 修改表后的数据,统一存储到特定的表中,之后通过代码同步两个库的数据
    有关求第n位xxx 的算法的问题
    C#获取枚举的特性描述工具方法
    wpf中嵌入另一个子进程exe像本地的一个页面那样
    emit 实现动态类,动态实现接口
    EF 支持泛型动态加载类访问数据库
    C# 通过 参数返回 C++ 指针
    C# 接收C++ dll 可变长字节或者 字符指针 char*
    健身篇
    Ubuntu 16.04安装Docker-Compose 与 Can't connect to docker from docker-compose
  • 原文地址:https://www.cnblogs.com/acles/p/2433883.html
Copyright © 2020-2023  润新知