.NET TIPS

画像ファイルを高速に読み込むには?[2.0のみ、C#、VB]

デジタルアドバンテージ 遠藤 孝信
2007/05/24

 JPEGファイルなどの画像ファイルを読み込んで画像オブジェクト(=Imageクラス(System.Drawing名前空間)のオブジェクト)を作成する際には、次のように、ImageクラスのFromFileメソッドを利用するのが最も手軽である。

Image img = Image.FromFile("picture.jpg");
Dim img As Image = Image.FromFile("picture.jpg")
FromFileメソッドによる画像ファイルの読み込み(上:C#、下:VB)

 しかしこの方法は内部で「画像データの検証」が行われているため、実はWin32 APIによる画像の読み込みなどに比べるとかなり低速である。

 .NET Framework 2.0では、ImageクラスのFromStreamメソッドを使用することにより、画像データの検証をスキップでき、高速に画像オブジェクトを作成できる。このメソッドを使用した画像ファイルの読み込みは次のようなコードにより行う。

FileStream fs = File.OpenRead("picture.jpg");
Image img = Image.FromStream(fs, false, false); // 検証なし
Dim fs As FileStream = File.OpenRead("picture.jpg")
Dim img As Image = Image.FromStream(fs, False, False); ' 検証なし
画像データの検証を行わない画像ファイルの読み込み(上:C#、下:VB)

 FromStreamメソッドの第3パラメータが、画像データの検証を行うかどうかを指定するためのものだ(第2パラメータでは色管理情報を使用するかどうかを指定する。これについてはリファレンス・マニュアルの「Image.FromStream メソッド (Stream, Boolean)」の項目を参照してほしい)。

サンプル・プログラムによる画像読み込み時間の比較

 次のサンプル・プログラムは、FromFileメソッドと、画像データの検証を行わないFromStreamメソッドで、画像オブジェクト作成にかかる時間を比較するためのものだ。

 このプログラムでは、C:\jpgsディレクトリにある画像を順に読み込んでImageオブジェクトを作成し、その画像の幅と高さを表示する。そして最後にその処理時間を表示する。これを2つのメソッドについて行っている。

// fastloadimg.cs

using System;
using System.Diagnostics;
using System.IO;
using System.Drawing;

class FastLoadImage {
  static void Main() {

    string dir = @"C:\jpgs";
    string[] jpgFiles = Directory.GetFiles(dir, "*.jpg");
    Stopwatch sw;

    // 画像データの検証をオフにしてロード
    sw = Stopwatch.StartNew();
    foreach (string jpg in jpgFiles) {
      using (FileStream fs = File.OpenRead(jpg))
      using (Image img = Image.FromStream(fs, false, false)) {
        Console.WriteLine("{0} : {1} x {2}", jpg, img.Width, img.Height);
      }
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds + "ミリ秒");
    // 出力例:
    // C:\jpgs\IMG_0001.jpg : 3456 x 2304
    // C:\jpgs\IMG_0002.jpg : 3456 x 2304
    // ……省略……
    // C:\jpgs\IMG_0199.jpg : 3456 x 2304
    // C:\jpgs\IMG_0200.jpg : 3456 x 2304
    // 651ミリ秒

    // Image.FromFileメソッドによるロード
    sw = Stopwatch.StartNew();
    foreach (string jpg in jpgFiles) {
      using (Image img = Image.FromFile(jpg)) {
        Console.WriteLine("{0} : {1} x {2}", jpg, img.Width, img.Height);
      }
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds + "ミリ秒");
    // 出力例:
    // C:\jpgs\IMG_0001.jpg : 3456 x 2304
    // C:\jpgs\IMG_0002.jpg : 3456 x 2304
    // ……省略……
    // C:\jpgs\IMG_0199.jpg : 3456 x 2304
    // C:\jpgs\IMG_0200.jpg : 3456 x 2304
    // 60069ミリ秒
  }
}

// コンパイル方法:csc fastloadimg.cs
FromFileメソッドとFromStreamメソッドの比較を行うC#のサンプル・プログラム(fastloadimg.cs)

' fastloadimg.vb

Imports System
Imports System.Diagnostics
Imports System.IO
Imports System.Drawing

Class FastLoadImage
  Shared Sub main()
    Dim dir As String = "C:\jpgs"
    Dim jpgFiles As String() = Directory.GetFiles(dir, "*.jpg")
    Dim sw As Stopwatch

    ' 画像データの検証をオフにしてロード
    sw = Stopwatch.StartNew()
    For Each jpg As String In jpgFiles
      Using fs As FileStream = File.OpenRead(jpg)
        Using img As Image = Image.FromStream(fs, False, False)
          Console.WriteLine("{0} : {1} x {2}", jpg, img.Width, img.Height)
        End Using
      End Using
    Next
    sw.Stop()
    Console.WriteLine(sw.ElapsedMilliseconds & "ミリ秒")
    ' 出力例:
    ' C:\jpgs\IMG_0001.jpg : 3456 x 2304
    ' C:\jpgs\IMG_0002.jpg : 3456 x 2304
    ' ……省略……
    ' C:\jpgs\IMG_0199.jpg : 3456 x 2304
    ' C:\jpgs\IMG_0200.jpg : 3456 x 2304
    ' 651ミリ秒

    ' Image.FromFileメソッドによるロード
    sw = Stopwatch.StartNew()
    For Each jpg As String In jpgFiles
      Using img As Image = Image.FromFile(jpg)
        Console.WriteLine("{0} : {1} x {2}", jpg, img.Width, img.Height)
      End Using
    Next
    sw.Stop()
    Console.WriteLine(sw.ElapsedMilliseconds & "ミリ秒")
    ' 出力例:
    ' C:\jpgs\IMG_0001.jpg : 3456 x 2304
    ' C:\jpgs\IMG_0002.jpg : 3456 x 2304
    ' ……省略……
    ' C:\jpgs\IMG_0199.jpg : 3456 x 2304
    ' C:\jpgs\IMG_0200.jpg : 3456 x 2304
    ' 60069ミリ秒
  End Sub
End Class

' コンパイル方法:vbc fastloadimg.vb
FromFileメソッドとFromStreamメソッドの比較を行うVBのサンプル・プログラム(fastloadimg.vb)

 コメントで記述している出力例は、筆者のPC(CPU:Intel Core 2 Duo 2.4GHz、メモリ:1Gbytes)でプログラムを実行したときのものだ。C:\jpgsディレクトリには200個のJPEGファイルが保存されている(ファイルの平均サイズは約1.9Mbytes)。処理時間から、画像データの検証を行わない方が90倍以上も速くなっていることが分かる。

 ただ実際には、画像データの検証を行っている場合には画像ファイル全体を一度に読み込むのに対して、検証を行っていない場合には必要に応じて画像ファイルを順次読み込んでいるようで、上記のサンプル・プログラムのように画像ファイルの先頭部分の読み込みだけで済む場合には高速だが、画像全体を表示する場合などでは速度差はあまりないようだ。

 なお、画像データの検証をスキップすることによる影響については、リファレンス・マニュアルに見当たらなかったため不明である。End of Article

利用可能バージョン:.NET Framework 2.0のみ
カテゴリ:クラス・ライブラリ 処理対象:ビットマップ
使用ライブラリ:Imageクラス(System.Drawing名前空間)

この記事と関連性の高い別の.NET TIPS
より高速にサムネイル画像(縮小画像)を作成するには?
PictureBoxコントロールにWeb画像を表示するには?
サムネイル画像(縮小画像)を作成するには?
画像の一部の領域を切り抜くには?
画像をファイルに保存するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間