[C#] 画像を拡大/縮小する

画像を簡単に拡大/縮小するにはGraphicsオブジェクトを使う。

まず結果となるビットマップを作成し、そのビットマップからGraphicsオブジェクトを作成。そして、そのGraphicsオブジェクトにソースビットマップを描画する。Graphicsオブジェクトにはビットマップの補間機能が用意されているので、InterpolationModeを指定することで補間モードを設定できる。

参考サイト

@IT:.NET TIPS 画像を高品質に拡大/縮小するには? – C#
http://www.atmarkit.co.jp/fdotnet/dotnettips/023resize/resize.html

[C#] 画像ファイルを高速に読み込むには

ちょっと古い記事(2007/05/24)だけど反応。

画像ファイルを高速に読み込むには?[2.0のみ、C#、VB] - @IT
http://www.atmarkit.co.jp/fdotnet/dotnettips/597fastloadimg/fastloadimg.html

この記事では画像ファイルからImageオブジェクトを作成する手順を解説している。気になったのは、Imageクラスのインスタンスを作成する際に「画像データの検証」をするかしないかのオプションがあり、それによって処理速度が大きく左右されるということ。

自分で検証してみる。そのために、フォームにPictureBoxを配置し、画像ファイルを読み込んで生成したImageオブジェクトをPictureBoxにアサインする、という簡単なテストプログラムを作成した。画像ファイルからどのようにImageオブジェクトを生成するか、3つの方法を試してみたい。

方法1: Image.FromFile()を使う

もっとも簡単な方法。

方法2: Image.FromStream()を使う

ファイル名だけ指定してFromStream()を使う。

方法3: Image.FromStream()を使う – イメージデータ検証無し

2つのオプション付きのFromStream()を試してみる。2番目の引数はカラーマネージメント情報の適用の有無、3番目の引数はイメージデータの検証の有無を指定する。共に false と指定。

処理速度

前回のエントリ同様に、4896×3264ピクセルのサンプル画像を使って処理時間を計測した。結果は方法3が他の2つより2桁も速い。「イメージデータの検証」を無しにすると読み込み速度を向上できることがわかった。

# 使用関数 処理時間
方法1 Image.FromFile() 132ms
方法2 Image.FromStream() 155ms
方法3 Image.FromStream() イメージデータ検証なし 2ms

環境: Windows 7 Ultimate SP1 (64bit), Intel Core i7 3.4GHz, RAM 16GB, Visual Studio 2012

イメージデータの検証は何をしているのか?

イメージデータの検証は何をしているのかという疑問が残った。Image.FromStreamメソッドはMSDNでは以下の通り説明されている。

Image.FromStream メソッド (Stream, Boolean, Boolean) オプションで埋め込み色管理情報の使用とイメージ データの検証を行い、指定したデータ ストリームから Image を作成します。 public static Image FromStream( Stream stream, bool useEmbeddedColorManagement, bool validateImageData ) useEmbeddedColorManagement データ ストリームに埋め込まれている色管理情報を使用する場合は true。それ以外の場合は false。 validateImageData イメージ データを検証する場合は true。それ以外の場合は false。 useEmbeddedColorManagement パラメーターは、データ ストリームに埋め込まれた色管理情報に従って、新しい Image に色補正を適用させるかどうかを指定します。 埋め込み情報には、ICC (International Color Consortium) プロファイル、ガンマ値、および色度情報を含めることができます。

useEmbeddedColorManagementの意味はなんとなくわかる。だけどvalidateImageDataの意味がわからない。「イメージデータを検証する」って何をしてるの?そういえば.NETってオープンソースでPC以外のプラットフォームにも移植されてたよな、と思って調べたらソースらしきものが見つかった。

Image.cs source code in C# .NET
http://www.dotnetframework.org/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/ REDBITS/ndp/fx/src/CommonUI/System/Drawing/Image@cs/1/Image@cs

このソースを見ると、validateImageDataがtrue、すなわち「イメージ データを検証する」とした場合、GDI+のGdipImageForceValidationが呼ばれている。だけど、ネットでGdipImageForceValidationの情報を探すも見つからず。かろうじてMSDNの以下ページに「This function forces validation of the image.」とだけ記載されていた。

Image Functions (Windows)
http://msdn.microsoft.com/en-us/library/ms534041(v=vs.85).aspx

更に情報を求めてネットを検索していたら、Windowsアプリを別プラットフォームで動かすWINEというプロジェクトを見つけた。

WineHQ – Run Windows applications on Linux, BSD, Solaris and Mac OS X
http://www.winehq.org/

GDI+の互換ライブラリが含まれているらしいのでダウンロードしてソースを閲覧したのだが、関数は存在したけど処理は実装されてなかった。Image.FromStreamメソッドの「イメージデータの検証」は何をやっているのか、残念ながらわからずじまい。

[C#] 品質を指定してJPEG画像を保存する

品質の指定は、Bitmap.Save() にエンコードパラメータを与えるだけ。

参考サイト

方法 : JPEG 圧縮レベルの設定
http://msdn.microsoft.com/ja-jp/library/bb882583(v=vs.110).aspx

[C#] 画像ファイルを書き出す

Bitmap.Saveメソッドに画像ファイル名を渡すと画像をファイルに保存できる。以下の画像形式の指定無しのメソッドを使うと画像はPNG形式に保存される。試しにファイル名の拡張子を”.jpg”にしてみたが、やはり画像はPNG形式で保存された。

PNG以外の形式に保存したければ、以下のようにファイル形式を指定する。

参考サイト

Image.Save メソッド (String) (System.Drawing)
http://msdn.microsoft.com/ja-jp/library/ktx83wah(v=vs.110).aspx

Image.Save メソッド (String, ImageFormat) (System.Drawing)
http://msdn.microsoft.com/ja-jp/library/9t4syfhh(v=vs.110).aspx

[C#] 画像ファイルを読み込む

C#では標準でGDI+が使われているので、画像の扱いは非常に楽になった。

画像ファイルは、Bitmapのコンストラクタに画像ファイル名を渡すだけで読み込める。このコンストラクターは、BMP、GIF、EXIG、JPG、PNG、および TIFF の各ファイル形式の画像を開くときに使用できる。

参考サイト

Bitmap コンストラクター (Type, String) (System.Drawing)
http://msdn.microsoft.com/ja-jp/library/47591zc7(v=vs.110).aspx

[C#] 定数を定義する

C/C++で定数を定義するのに#defineマクロを使った。C#では?

C#で#defineマクロは使えるのか?

C#にも#defineは存在する。だけど定数の定義には使えない。

#define (C# リファレンス) – Visual Studio 2008
http://msdn.microsoft.com/ja-jp/library/yt3yck0x(v=vs.90).aspx

#define ディレクティブを使用して、通常 C および C++ で行うように定数値を宣言することはできません。C# の定数は、クラスまたは構造体の静的メンバとして定義することができます。そのような定数がいくつかある場合は、それを保持するための “Constants” クラスを個別に作成することを検討してください。

ちなみに、C#で使えるプリプロセッサディレクティブに関しては以下参照。

C# プリプロセッサ ディレクティブ
http://msdn.microsoft.com/ja-jp/library/ed8yd1ha(v=vs.90).aspx

C#で定数を定義する方法

以下のサイトに説明あり。

方法 : C# で定数を定義する
http://msdn.microsoft.com/ja-jp/library/vstudio/bb397677.aspx

C# では、C および C++ で一般的な #define プロセッサ ディレクティブを使用する方法で定数は定義できません。

整数型 (int、byte など) の定数値を定義するには、列挙型を使用します。 詳細については、「enum (C# リファレンス)」を参照してください。

整数型以外の定数を定義する 1 つの方法としては、Constants という名前の 1 つの静的クラスにそれらをグループ化します。 これを行うには、次の例に示すように、クラス名の前に定数へのすべての参照を付ける必要があります。

クラスの再利用性を高めるための工夫

アプリが多数のクラスで構成されている場合、それぞれのクラスがConstantsクラスを参照するようにしてしまうと、クラスの再利用性が低下する。言い換えるならば、あるクラスを別のプロジェクトにコピーしてビルドすると「Constantsクラスが未定義」と叱られるわけだ。できればConstantsクラスが無いプロジェクトにコピーしても、とりあえずビルドが通るようなクラスにしておきたい。 クラスの再利用性を高めるためには、クラス間の依存性を高くしないことが重要。そのためには、予めクラス内にデフォルトの動作定数を持たせておいて、プログラム起動時に必要に応じてそれを書き換えるといったような実装をするのも一案。コーディングの手間は若干増えるけど、クラスの再利用性は高まるはず。

[C#] CSVファイルを書き出す

CSVファイルへの書き出しは、書き出す項目をカンマで区切って連結する以外は、テキストファイルへの書き出しと変わらない。

[C#] CSVファイルを読み込む

VBで便利に使えるCSVファイルのパーサー(Microsoft.VisualBasic.FileIO.TextFieldParser)がC#からでも使える。これを使うとCSVファイルの読み込みはとっても簡単。

参考サイト

CSVファイルを読み込むには?[2.0のみ、C#、VB] - @IT
http://www.atmarkit.co.jp/fdotnet/dotnettips/487csvparser/csvparser.html

[C#] テキストファイルを書き出す

テキストファイルの書き出しにはStreamWriterクラス (System.IO)を使う。

ファイルが存在すれば上書き

テキストの書き出しにはWriteやWriteLineメソッドを使う。

エラーが発生すると例外がスローされる。

このサンプルのようにエンコーディング指定が無い場合は、デフォルトでUTF-8となる。もしShift JISで書き出したければエンコーディングの指定が必要(後述)。

既存ファイルへの追加書き込み

追加書き込みフラグ付きのコンストラクタを使うと、ファイルが存在する場合に上書きするか、ファイルの末尾に追加するかを指定できる。

Shift JISでの書き出し

UTF-8以外の文字コードで書き出すには、エンコーディングを指定する必要がある。

参考サイト

StreamWriter クラス (System.IO)
http://msdn.microsoft.com/ja-jp/library/system.io.streamwriter(v=vs.110).aspx

[C#] テキストファイルを読み込む

StreamReaderクラス (System.IO) を使うと、テキストファイルを簡単に読み込むことができる。このクラスはTextReaderクラスの派生クラスである。

ファイルの読み込みは、ファイルのオープン、読み込み、クローズの3つの手順から成る。

ファイル全体を一気に読み込む

ReadToEndメソッドを使うと、ファイル全体を一気に読み込むことができる。

エラーが発生すると例外がスローされる。

このサンプルでは文字コードがShift-JISのテキストファイルを読み込んでいる。

文字エンコードのデフォルトはUTF-8なので、UTF-8のテキストファイルを読み込む場合にはEncodingの指定は省略可能。誤ったエンコードを指定すると(たとえばエンコードにUTF-8を指定してShift-JISファイルを読み込むような場合)、読み込まれたテキストが文字化けするので注意が必要だ。

オープンしたファイルは必ずクローズする必要がある。usingステートメントを使うと、明示的にクローズする必要は無くなる。

ファイルを1行ずつ読み込む

ReadLineメソッドを使うと、ファイルから1行だけ読み込むことができる。

“n”、”r”、”rn” の何れかのコードが見つかると行末と認識される。ReadLineメソッドが返す文字列からは行末コードは除去されている。ファイルの末尾に到達すると、ReadLineメソッドはnullを返す。

参考サイト

StreamReader クラス (System.IO)
http://msdn.microsoft.com/ja-jp/library/system.io.streamreader(v=vs.110).aspx