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/