ExifLib

最近のデジカメやスマートフォン(もちろんWindows Phoneも)などで撮った写真には、それが縦撮影(Portrail)か横撮影(Landscape)かを示す向き情報(Orientation)がExif(EXchangeable Image file Format)に格納されています。

Windows Phoneで撮った写真や格納されている写真を表示しようとするとき、デフォルトが横撮影なので、この情報を反映させないと縦のものが横に寝た状態で表示されてしまいます。

WPFですとBitmapSource.Metadata プロパティから BitmapMetadata として取得できますが、Silverlight にはこのようなプロパティがないので、自前で解析しなければなりません。

ExifLib は ExifReader クラスを持ち、Exif データの抽出と解析を行ってくれるライブラリです。Tim Heuer が彼のブログで 、Windows Phone の PhotoChooserTask や CameraCaptureTask を使って取得した写真・画像を ExifLib を使って正しい方向に回転するサンプルを公開しています。

CameraCaptureTask が返す Stream に対応するよう、元々の ExifReader の ExifReader.cs に以下のコードを追加している点に注意してください。

public static JpegInfo ReadJpeg(Stream FileStream, string FileName)

{

  DateTime now = DateTime.Now;

  ExifReader reader = new ExifReader(FileStream);

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

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

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

  return reader.info;

}

回転を行っているコードは以下の通りです。

public enum ExifOrientation

{

  TopLeft = 1,

  BottomRight = 3,

  TopRight = 6,

  BottomLeft = 8,

  Undefined = 9

}

void OnCameraCaptureCompleted(object sender, PhotoResult e)

{

  e.ChosenPhoto.Position = 0;

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

 

  _width = info.Width;

  _height = info.Height;

  _orientation = info.Orientation;

 

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

 

  switch (info.Orientation)

  {

    case ExifOrientation.TopLeft:

    case ExifOrientation.Undefined:

         _angle = 0;

         break;

    case ExifOrientation.TopRight:

         _angle = 90;

         break;

    case ExifOrientation.BottomRight:

         _angle = 180;

         break;

    case ExifOrientation.BottomLeft:

         _angle = 270;

         break;

  }

 

  if (_angle > 0d)

  {

    capturedImage = RotateStream(e.ChosenPhoto, _angle);

  }

  else

  {

    capturedImage = e.ChosenPhoto;

  }

 

  BitmapImage bmp = new BitmapImage();

  bmp.SetSource(capturedImage);

 

  ChosenPicture.Source = bmp;

}