はじめに
「Windows phoneで画像エフェクトアプリを作ろう!」
エフェクト処理の高速化と、
- サンプルプログラム
(15. 3KB)
エフェクト処理の高速化を行う
前回のさいごにBitmap.
LockBitsメソッドを使うと、
Image.
private void EffectGrayScale(ref Bitmap bmp)
{
Rectangle bmpRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
// ImageLockModeに使用できる値は、ReadWrite、ReadOnly、WriteOnly。
// ここでは加工処理を行うのでReadWriteを指定しています
System.Drawing.Imaging.ImageLockMode mode
= System.Drawing.Imaging.ImageLockMode.ReadWrite;
// 明示的にPixelFormatを指定
System.Drawing.Imaging.PixelFormat format
= System.Drawing.Imaging.PixelFormat.Format24bppRgb;
// システムメモリへBitmapをロックする
System.Drawing.Imaging.BitmapData bmpData
= bmp.LockBits(bmpRect, mode, format);
// Bitmapデータの最初のラインのアドレスの取得
IntPtr p = bmpData.Scan0;
// Bitmapデータを格納するピクセル配列の確保
int numBytes = bmp.Width * bmp.Height * 3;
byte[] rgbValues = new byte[numBytes];
// Bitmapデータからピクセル配列へコピーする
System.Runtime.InteropServices.Marshal.Copy(p, rgbValues, 0, numBytes);
for (int idx = 0; idx < rgbValues.Length; idx += 3)
{
// RGB値の取得
byte r = rgbValues[idx];
byte g = rgbValues[idx + 1];
byte b = rgbValues[idx + 2];
// 平均してグレイスケール値を求める
byte avg = (byte)((r + g + b) / 3);
// RGB値の設定
rgbValues[idx] = avg;
rgbValues[idx + 1] = avg;
rgbValues[idx + 2] = avg;
}
// ピクセル配列からBitmapデータへ書き戻す
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, p, numBytes);
// システムメモリへロックしたBitmapを解除する
bmp.UnlockBits(bmpData);
}
適度なサイズの画像でSetPixel/
写真全体を表示可能な様に縦横比を合わせてリサイズする
技術の進歩とともに撮影可能なサイズは増加の一方です。国内で発売された中で一番大きなディスプレイを持つ端末でもFVGA
大きな写真の全体像をディスプレイに表示するには、
デスクトップ版の.NET Frameworkでは、
写真のサイズが表示すべき領域より大きい場合のみリサイズを行うResizeBitmapメソッドを以下に示します。
private Bitmap ResizeBitmap(Bitmap srcBmp, int dispWidth, int dispHeight)
{
Bitmap retBmp = null;
if ((srcBmp.Height > dispHeight) ||
(srcBmp.Width > dispWidth))
{
int h = srcBmp.Height;
int w = srcBmp.Width;
// 画像の高さが表示領域の高さよりも大きい場合、
// 表示領域の高さに収まる様に比率を計算する
if (h > dispHeight)
{
double temp = h;
h = dispHeight;
w = (int)(w * (h / temp));
}
// 画像の幅が表示領域の幅よりも大きい場合、
// 表示領域の幅に収まる様に比率を計算する
if (w > dispWidth)
{
double temp = w;
w = dispWidth;
h = (int)(h * (w / temp));
}
// リサイズ後の画像を格納するBitmapを生成
Bitmap resizeBmp = new Bitmap(w, h);
// リサイズ前の画像のサイズを定義
Rectangle srcRect = new Rectangle(0, 0, srcBmp.Width, srcBmp.Height);
// リサイズ後の画像のサイズを定義
Rectangle resizeRect = new Rectangle(0, 0, w, h);
using (Graphics g = Graphics.FromImage(resizeBmp))
{
g.DrawImage(srcBmp, resizeRect, srcRect, GraphicsUnit.Pixel);
}
retBmp = resizeBmp;
}
return retBmp;
}
作成したResizeBitmapメソッドを利用方法を示します。このアプリケーションPictureEffectでは、
this.
private void menuSelectPicture_Click(object sender, EventArgs e)
{
Microsoft.WindowsMobile.Forms.SelectPictureDialog dlg
= new Microsoft.WindowsMobile.Forms.SelectPictureDialog();
dlg.Title = "加工する画像を選択してください";
if (dlg.ShowDialog() != DialogResult.OK)
{
return;
}
// ファイルパスからBitmapを生成する
//this.OriginalBmp = new Bitmap(dlg.FileName);
Bitmap pictBmp = new Bitmap(dlg.FileName);
// 現在表示しているディスプレイの大きさに
// マッチする様にリサイズする
this.OriginalBmp = this.ResizeBitmap(
pictBmp, pictureBox1.Width, pictureBox1.Height);
pictureBox1.Image = this.OriginalBmp;
}
加工した画像を保存する
せっかくですのでエフェクトをかけた画像を保存してみましょう。BitmapクラスにはSaveメソッドが用意されています。これで指定したファイルパスやストリームに画像を保存することが可能です。
MainMenuに
private void menuSave_Click(object sender, EventArgs e)
{
// 保存先のファイルパスを取得
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "jpeg file(*.jpg)|*.jpg";
dlg.ShowDialog();
// 保存する画像フォーマットをJPEG形式に
System.Drawing.Imaging.ImageFormat imgFmt
= System.Drawing.Imaging.ImageFormat.Jpeg;
// pictureBox1に指定しているImageをファイル保存
pictureBox1.Image.Save(dlg.FileName, imgFmt);
}
上記のコードではImageFormat.
画像を転送する場合などストリームで保存するほうが都合のよい時は、
// メモリを用いたストリームの作成
System.IO.MemoryStream memStrm
= new System.IO.MemoryStream();
// 保存する画像フォーマットをJPEG形式に
System.Drawing.Imaging.ImageFormat imgFmt
= System.Drawing.Imaging.ImageFormat.Jpeg;
// pictureBox1に指定しているImageをストリームへ保存
pictureBox1.Image.Save(memStrm, imgFmt);
さいごに
連載第8回、
エフェクトを掛けた後の画像をflickrやTumblrなどのフォトストレージサービスのWebAPIを使ってシェアすると、
今回は以上で終わりです。ありがとうございました。