画像を縦横に拡大すると画像に隙間が生まれます。この隙間を埋める手法を補間と呼び、C#ではGraphicsクラスのInterpolationModeプロパティを設定することで、DrawImageメソッドが補間処理を行ってくれます。
アンチエイリアスは斜めの線を描画した時にギザギザになるのをなめらかにする処理ですが、C#ではGraphicsクラスのSmoothingModeプロパティで指定することができます。
さて、どのように変化するのでしょうか?
以下は画像を拡大縮小するメソッドと回転させるメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
public partial class Form1 : Form { Bitmap ExpandBitmap(Bitmap bitmap) { if (bitmap == null) return null; double magnification = (double)(numericUpDownMagnification.Value) / 100; int newWidth = (int)(bitmap.Width * magnification); int newHeight = (int)(bitmap.Height * magnification); Bitmap newBitmap = new Bitmap(newWidth, newHeight); Graphics g = Graphics.FromImage(newBitmap); if (radioButtonDefault.Checked) g.InterpolationMode = InterpolationMode.Default; if (radioButtonLow.Checked) g.InterpolationMode = InterpolationMode.Low; if (radioButtonHigh.Checked) g.InterpolationMode = InterpolationMode.High; if (radioButtonNearestNeighbor.Checked) g.InterpolationMode = InterpolationMode.NearestNeighbor; if (radioButtonHighQualityBilinear.Checked) g.InterpolationMode = InterpolationMode.HighQualityBilinear; if (radioButtonHighQualityBicubic.Checked) g.InterpolationMode = InterpolationMode.HighQualityBicubic; if (radioButtonBilinear.Checked) g.InterpolationMode = InterpolationMode.Bilinear; if (radioButtonBicubic.Checked) g.InterpolationMode = InterpolationMode.Bicubic; if (radioButtonAntiAlias.Checked) g.SmoothingMode = SmoothingMode.AntiAlias; if (radioButtonDefault2.Checked) g.SmoothingMode = SmoothingMode.Default; if (radioButtonHighQuality.Checked) g.SmoothingMode = SmoothingMode.HighQuality; if (radioButtonHighSpeed.Checked) g.SmoothingMode = SmoothingMode.HighSpeed; if (radioButtonNone.Checked) g.SmoothingMode = SmoothingMode.None; g.DrawImage(bitmap, new Rectangle(0, 0, newWidth, newHeight)); g.Dispose(); return newBitmap; } Bitmap RotateBitmap(Bitmap bitmap) { if (bitmap == null) return null; List<Point> points = new List<Point>(); points.Add(new Point(0, 0)); points.Add(new Point(bitmap.Width, 0)); points.Add(new Point(0, bitmap.Height)); points = points.Select(x => new Point(x.X - bitmap.Width / 2, x.Y - bitmap.Height / 2)).ToList(); { int angle = (int)numericUpDownAngle.Value; double rad = Math.PI * angle / 180; List<Point> points2 = new List<Point>(); foreach (Point pt in points) { int x = (int)(pt.X * Math.Cos(rad) + pt.Y * Math.Sin(rad)); int y = (int)(-pt.X * Math.Sin(rad) + pt.Y * Math.Cos(rad)); points2.Add(new Point(x, y)); } points = points2; } int widthHalf = points.Max(x => Math.Abs(x.X)); int heightHalf = points.Max(x => Math.Abs(x.Y)); int newWidth = widthHalf * 2; int newHeight = heightHalf * 2; points = points.Select(x => new Point(x.X + widthHalf, x.Y + heightHalf)).ToList(); Bitmap newBitmap = new Bitmap(newWidth, newHeight); Graphics g = Graphics.FromImage(newBitmap); if (radioButtonDefault.Checked) g.InterpolationMode = InterpolationMode.Default; if (radioButtonLow.Checked) g.InterpolationMode = InterpolationMode.Low; if (radioButtonHigh.Checked) g.InterpolationMode = InterpolationMode.High; if (radioButtonNearestNeighbor.Checked) g.InterpolationMode = InterpolationMode.NearestNeighbor; if (radioButtonHighQualityBilinear.Checked) g.InterpolationMode = InterpolationMode.HighQualityBilinear; if (radioButtonHighQualityBicubic.Checked) g.InterpolationMode = InterpolationMode.HighQualityBicubic; if (radioButtonBilinear.Checked) g.InterpolationMode = InterpolationMode.Bilinear; if (radioButtonBicubic.Checked) g.InterpolationMode = InterpolationMode.Bicubic; if (radioButtonAntiAlias.Checked) g.SmoothingMode = SmoothingMode.AntiAlias; if (radioButtonDefault2.Checked) g.SmoothingMode = SmoothingMode.Default; if (radioButtonHighQuality.Checked) g.SmoothingMode = SmoothingMode.HighQuality; if (radioButtonHighSpeed.Checked) g.SmoothingMode = SmoothingMode.HighSpeed; if (radioButtonNone.Checked) g.SmoothingMode = SmoothingMode.None; g.DrawImage(bitmap, points.ToArray(), new Rectangle(0, 0, bitmap.Width, bitmap.Height), GraphicsUnit.Pixel); g.Dispose(); return newBitmap; } } |
画像をドラッグアンドドロップするとフォーム上に画像を表示させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); AllowDrop = true; } Bitmap Bitmap = null; protected override void OnDragOver(DragEventArgs drgevent) { if (drgevent.Data.GetDataPresent(DataFormats.FileDrop)) drgevent.Effect = DragDropEffects.All; base.OnDragOver(drgevent); } protected override void OnDragDrop(DragEventArgs drgevent) { if (drgevent.Data.GetDataPresent(DataFormats.FileDrop)) { string[] files = (string[])drgevent.Data.GetData(DataFormats.FileDrop); string filePath = files[0]; Image image = Image.FromFile(filePath); Bitmap = new Bitmap(image); image.Dispose(); Invalidate(); } base.OnDragDrop(drgevent); } protected override void OnPaint(PaintEventArgs e) { if (Bitmap != null) { Bitmap bitmap = null; bitmap = RotateBitmap(Bitmap); bitmap = ExpandBitmap(bitmap); e.Graphics.DrawImage(bitmap, new Point(0, 0)); } base.OnPaint(e); } } |
アップダウンコントロールの値が変化したとき、選択されているラジオボタンが変更されたときもビットマップを再描画します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
public partial class Form1 : Form { private void numericUpDownAngle_ValueChanged(object sender, EventArgs e) { Invalidate(); } private void numericUpDownMagnification_ValueChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonDefault_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonLow_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonHigh_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonNearestNeighbor_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonBilinear_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonHighQualityBilinear_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonBicubic_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonHighQualityBicubic_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonInvalid_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonNone_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonDefault2_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonHighSpeed_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonHighQuality_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonAntiAlias_CheckedChanged(object sender, EventArgs e) { Invalidate(); } private void radioButtonInvalid2_CheckedChanged(object sender, EventArgs e) { Invalidate(); } } |
さて実行してみましょう。拡大率を大きくするとInterpolationModeを変更することで変化が確認できます。SmoothingModeを変更しても変化はほとんどみられません。