EXIFのOrientationタグの値に基づいて画像を回転し、適切な方向に戻して再保存する方法。 また逆に、Orientationタグを設定して画像を回転した状態で保存する方法。
Orientationタグから画像の方向を復元する
Bitmap.PropertyItemsプロパティを参照すると画像に付与されているEXIFの情報を取得することができる。 ID(PropertyItem.Id)が0x0112
のタグがOrientationタグなので、このIDを持つタグの値(PropertyItem.Value)を参照することで画像の方向を知ることができる。 画像の回転にはImage.RotateFlipメソッドを使うことができる。
using System;
using System.Drawing;
using System.Drawing.Imaging;
class Sample {
static void Main()
{
// 元の画像を開く
using (var origin = new Bitmap("origin.jpg")) {
var rotation = RotateFlipType.RotateNoneFlipNone;
// 画像に付与されているEXIF情報を列挙する
foreach (var item in origin.PropertyItems) {
if (item.Id != 0x0112)
continue;
// IFD0 0x0112; Orientationの値を調べる
switch (item.Value[0]) {
case 3:
// 時計回りに180度回転しているので、180度回転して戻す
rotation = RotateFlipType.Rotate180FlipNone;
break;
case 6:
// 時計回りに270度回転しているので、90度回転して戻す
rotation = RotateFlipType.Rotate90FlipNone;
break;
case 8:
// 時計回りに90度回転しているので、270度回転して戻す
rotation = RotateFlipType.Rotate270FlipNone;
break;
}
}
// 元の画像を複製する
using (var rotated = (Bitmap)origin.Clone()) {
// 指定された角度だけ画像を回転する
rotated.RotateFlip(rotation);
// BMP形式で保存
rotated.Save("rotated.bmp", ImageFormat.Bmp);
}
}
}
}
Imports System
Imports System.Drawing
Imports System.Drawing.Imaging
Class MainClass
Shared Sub Main()
' 元の画像を開く
Using origin As New Bitmap("origin.jpg")
Dim rotation As RotateFlipType = RotateFlipType.RotateNoneFlipNone
' 画像に付与されているEXIF情報を列挙する
For Each item As PropertyItem In origin.PropertyItems
If item.Id <> &H0112 Then Continue For
' IFD0 0x0112; Orientationの値を調べる
Select Case item.Value(0)
Case 3
' 時計回りに180度回転しているので、180度回転して戻す
rotation = RotateFlipType.Rotate180FlipNone
Case 6
' 時計回りに270度回転しているので、90度回転して戻す
rotation = RotateFlipType.Rotate90FlipNone
Case 8
' 時計回りに90度回転しているので、270度回転して戻す
rotation = RotateFlipType.Rotate270FlipNone
End Select
Next
' 元の画像を複製する
Using rotated As Bitmap = DirectCast(origin.Clone(), Bitmap)
' 指定された角度だけ画像を回転する
rotated.RotateFlip(rotation)
' BMP形式で保存
rotated.Save("rotated.bmp", ImageFormat.Bmp)
End Using
End Using
End Sub
End Class
上記の例では水平方向・垂直方向に反転している画像については考慮していない。 Orientationタグは次のいずれかの値を取りうる。
Orientationタグの値 | 方向を元に戻すために施す処理 |
---|---|
1 | 不要(回転・反転なし) |
2 | 水平方向に反転 |
3 | 時計回りに180度回転 |
4 | 垂直方向に反転 |
5 | 水平方向に反転+時計回りに270度回転 |
6 | 時計回りに90度回転 |
7 | 水平方向に反転+時計回りに90度回転 |
8 | 時計回りに270度回転 |
Orientationタグを設定して保存する
逆に、Orientationタグを設定して画像を保存する方法。 EncoderParameterを使ってEncoder.Transformationと以下の値を指定することで、画像を回転(もしくは反転)された状態で表示されるように指定することが出来る。
指定する値 | 画像の回転・反転方向 |
---|---|
EncoderValue.TransformRotate90 | 時計回りに90度回転するようにする |
EncoderValue.TransformRotate180 | 時計回りに180度回転するようにする |
EncoderValue.TransformRotate270 | 時計回りに270度回転するようにする |
EncoderValue.TransformFlipHorizontal | 水平方向に反転するようにする |
EncoderValue.TransformFlipVertical | 垂直方向に反転するようにする |
using System;
using System.Drawing;
using System.Drawing.Imaging;
class Sample {
static void Main()
{
// 元の画像を開く
using (var origin = new Bitmap("origin.jpg")) {
// JPEGのコーデック情報(ImageCodecInfo)を取得
ImageCodecInfo jpegCodecInfo = null;
foreach (var codecInfo in ImageCodecInfo.GetImageEncoders()) {
// FormatIdがJpegのものを探す
if (codecInfo.FormatID == ImageFormat.Jpeg.Guid) {
jpegCodecInfo = codecInfo;
break;
}
}
// エンコーダに渡すパラメータを設定する
var parameters = new EncoderParameters(1);
// 画像を270度回転した状態で表示させるようにする
parameters.Param[0] = new EncoderParameter(Encoder.Transformation, (long)EncoderValue.TransformRotate270);
// コーデック情報とパラメータを指定して保存
origin.Save("transformed.jpg", jpegCodecInfo, parameters);
}
}
}
Imports System
Imports System.Drawing
Imports System.Drawing.Imaging
Class Sample
Shared Sub Main()
' 元の画像を開く
Using origin As Image = Bitmap.FromFile("origin.jpg")
' JPEGのコーデック情報(ImageCodecInfo)を取得
Dim jpegCodecInfo As ImageCodecInfo = Nothing
For Each codecInfo As ImageCodecInfo In ImageCodecInfo.GetImageEncoders()
' FormatIdがJpegのものを探す
If codecInfo.FormatID = ImageFormat.Jpeg.Guid Then
jpegCodecInfo = codecInfo
Exit For
End If
Next
' エンコーダに渡すパラメータを設定する
Dim parameters As New EncoderParameters(1)
' 画像を270度回転した状態で表示させるようにする
parameters.Param(0) = New EncoderParameter(Encoder.Transformation, CLng(EncoderValue.TransformRotate270))
' コーデック情報とパラメータを指定して保存
origin.Save("transformed.jpg", jpegCodecInfo, parameters)
End Using
End Sub
End Class
なお、この方法を使ってもロスレスでの回転とはならない模様(保存時にJPEGへの再エンコードが行われる)。