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

 

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

 

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

Android 拍照后图片方向不对 手机拍照方向不一致_Android 拍照后图片方向不对

解释一下啊。

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

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

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

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

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

 

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

 

要修正方向不对的问题,就需要知道拍照后照片的方向。要知道照片的方向,就要使用到另一个老外的一个类库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/