|
.NET TIPS
より高速にサムネイル画像(縮小画像)を作成するには?[2.0のみ、C#、VB]
デジタルアドバンテージ 遠藤 孝信
2007/06/14 |
|
|
「TIPS:サムネイル画像(縮小画像)を作成するには?」では、Imageクラス(System.Drawing名前空間)のGetThumbnailImageメソッドによりサムネイル画像を作成する方法について紹介した。そのTIPSのサンプル・プログラムでは、元の画像を読み込むために(画像オブジェクトを作成するために)ImageクラスのFromFileメソッドを使用している。
しかし、「TIPS:画像ファイルを高速に読み込むには?」で紹介しているように、.NET Framework 2.0ではImageクラスのFromStreamメソッドにより、FromFileメソッドよりも高速に画像オブジェクト(Imageオブジェクト)を作成することができる。
そこで本稿では、より高速にサムネイル画像を作成するための、FromStreamメソッドとGetThumbnailImageメソッドを組み合わせた場合のコードを紹介し、FromFileメソッドを使用した場合と速度を比較してみる。また、さらに高速にサムネイル画像を作成するための方法として、Exif情報から直接サムネイル画像を取得する方法についても触れる。
FromFileメソッド+GetThumbnailImageメソッド
まず冒頭のTIPSと同様の方法である、ImageクラスのFromFileメソッドとGetThumbnailImageメソッドの組み合わせによりサムネイル画像を作成するサンプル・プログラムを以下に示す。
このプログラムでは、C:\jpgsディレクトリにあるJPEGファイルを順に読み込んでImageオブジェクトを作成し、それを基に160ピクセルX120ピクセル*のサムネイル画像を作成してファイルに保存する。また、すべての処理にかかる時間をStopwatchクラス(System.Diagnostics名前空間)により計測する。
* 最近のデジタル・カメラで撮影したJPEG画像には、たいていこのサイズのサムネイル画像がそのExif情報部分に格納されているようである。
|
// normalthumbnail.cs
// Image.FromFileメソッド+GetThumbnailImageメソッドによる作成
using System;
using System.IO;
using System.Drawing;
using System.Diagnostics;
class NormalThumbnail {
static void Main() {
string dir = @"C:\jpgs"; // 画像のあるディレクトリ
string[] jpgFiles = Directory.GetFiles(dir, "*.jpg");
Stopwatch sw = Stopwatch.StartNew();
foreach (string jpg in jpgFiles) {
Console.WriteLine(jpg);
// 画像オブジェクトの作成
Image orig = Image.FromFile(jpg);
// サムネイルの作成
Image thumbnail = orig.GetThumbnailImage(
160, 120, delegate { return false; }, IntPtr.Zero);
// サムネイルの保存
thumbnail.Save("tn_" + Path.GetFileName(jpg),
System.Drawing.Imaging.ImageFormat.Jpeg);
orig.Dispose();
thumbnail.Dispose();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds + "ミリ秒");
// 出力例:53109ミリ秒
}
}
// コンパイル方法:csc normalthumbnail.cs
|
|
C#のサンプル・プログラム(normalthumbnail.cs) |
|
' normalthumbnail.vb
' Image.FromFileメソッド+GetThumbnailImageメソッドによる作成
Imports System
Imports System.IO
Imports System.Drawing
Imports System.Diagnostics
Class CreateThumbnailTest
Shared Function dummy() As Boolean
Return False
End Function
Shared Sub Main()
Dim dir As String = "C:\jpgs" ' 画像のあるディレクトリ
Dim jpgFiles As String() = Directory.GetFiles(dir, "*.jpg")
Dim sw As Stopwatch = Stopwatch.StartNew()
For Each jpg As String In jpgFiles
Console.WriteLine(jpg)
' 画像オブジェクトの作成
Dim orig As Image = Image.FromFile(jpg)
' サムネイルの作成
Dim thumbnail As Image = orig.GetThumbnailImage(160, 120, _
New Image.GetThumbnailImageAbort(AddressOf dummy), _
IntPtr.Zero)
' サムネイルの保存
thumbnail.Save("tn_" + Path.GetFileName(jpg), _
System.Drawing.Imaging.ImageFormat.Jpeg)
orig.Dispose()
thumbnail.Dispose()
Next
sw.Stop()
Console.WriteLine(sw.ElapsedMilliseconds & "ミリ秒")
' 出力例:53109ミリ秒
End Sub
End Class
' コンパイル方法:vbc normalthumbnail.vb
|
|
VBのサンプル・プログラム(normalthumbnail.vb) |
|
コメントで出力例として記述している処理時間(53109ミリ秒)は、筆者のPC(CPU:Intel Core 2 Duo 2.4GHz、メモリ:2Gbytes)で実行したときのものだ。C:\jpgsディレクトリには200個のデジカメ画像(JPEGファイル)が保存されている(ファイルの平均サイズは約1.9Mbytes)。
FromStreamメソッド+GetThumbnailImageメソッド
次のサンプル・プログラムは、ImageクラスのFromStreamメソッドにより画像オブジェクトを作成し、GetThumbnailImageメソッドによりサムネイル画像を作成する。
// fastthumbnail.cs
// Image.FromStreamメソッド+GetThumbnailImageメソッドによる作成
using System;
using System.IO;
using System.Drawing;
using System.Diagnostics;
class FastThumbnail {
static void Main() {
string dir = @"C:\jpgs"; // 画像のあるディレクトリ
string[] jpgFiles = Directory.GetFiles(dir, "*.jpg");
Stopwatch sw = Stopwatch.StartNew();
foreach (string jpg in jpgFiles) {
Console.WriteLine(jpg);
using (FileStream fs = File.OpenRead(jpg)) {
// 画像の読み込み
Image orig = Image.FromStream(fs, false, false);
// サムネイルの作成
Image thumbnail = orig.GetThumbnailImage(
160, 120, delegate { return false; }, IntPtr.Zero);
// サムネイルの保存
thumbnail.Save("tn_" + Path.GetFileName(jpg),
System.Drawing.Imaging.ImageFormat.Jpeg);
orig.Dispose();
thumbnail.Dispose();
}
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds + "ミリ秒");
// 出力例:9492ミリ秒
}
}
// コンパイル方法:csc fastthumbnail.cs
|
|
C#のサンプル・プログラム(fastthumbnail.cs) |
|
' fastthumbnail.vb
' Image.FromStreamメソッド+GetThumbnailImageメソッドによる作成
Imports System
Imports System.IO
Imports System.Drawing
Imports System.Diagnostics
Class FastThumbnail
Shared Function dummy() As Boolean
Return False
End Function
Shared Sub Main()
Dim dir As String = "C:\jpgs" ' 画像のあるディレクトリ
Dim jpgFiles As String() = Directory.GetFiles(dir, "*.jpg")
Dim sw As Stopwatch = Stopwatch.StartNew()
For Each jpg As String In jpgFiles
Console.WriteLine(jpg)
Using fs As FileStream = File.OpenRead(jpg)
' 画像の読み込み
Dim orig As Image = Image.FromStream(fs, False, False)
' サムネイルの作成
Dim thumbnail As Image = orig.GetThumbnailImage(160, 120, _
New Image.GetThumbnailImageAbort(AddressOf dummy), _
IntPtr.Zero)
' サムネイルの保存
thumbnail.Save("tn_" + Path.GetFileName(jpg), _
System.Drawing.Imaging.ImageFormat.Jpeg)
orig.Dispose()
thumbnail.Dispose()
End Using
Next
sw.Stop()
Console.WriteLine(sw.ElapsedMilliseconds & "ミリ秒")
' 出力例:9492ミリ秒
End Sub
End Class
' コンパイル方法:vbc fastthumbnail.vb
|
|
VBのサンプル・プログラム(fastthumbnail.vb) |
|
FromStreamメソッドはファイル全体を一度に読み込まず、かつ、通常はサムネイル画像がJPEGファイルの先頭部分に格納されているため、筆者の環境では、処理速度はFromFileメソッドで画像オブジェクトを作成した先ほどのサンプル・プログラムよりも約6倍速くなっている。
Exif情報内のサムネイル画像の読み込み
次のサンプル・プログラムでは、JPEGファイルのExif情報に格納されているサムネイル画像のデータ(タグ番号は0x501b)をバイト配列のデータとして取り出し、そこからサムネイル画像の画像オブジェクトを作成する。
なお、Exif情報内のデータの取得に関しては「TIPS:デジカメ画像のExif情報を取得するには?」を、バイト配列のデータから画像オブジェクトを作成する方法については「TIPS:バイト配列→画像オブジェクト/画像オブジェクト→バイト配列の変換を行うには?」を参照していただきたい。
// fasterthumbnail.cs
// FromStreamメソッドを使ったExifデータの読み込み
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
class FasterThumbnail {
static void Main() {
string dir = @"C:\jpgs"; // 画像のあるディレクトリ
string[] jpgFiles = Directory.GetFiles(dir, "*.jpg");
ImageConverter imgconv = new ImageConverter();
Stopwatch sw = Stopwatch.StartNew();
foreach (string jpg in jpgFiles) {
Console.WriteLine(jpg);
using (FileStream fs = File.OpenRead(jpg)) {
// 画像オブジェクトの作成
Image orig = Image.FromStream(fs, false, false);
int[] pils = orig.PropertyIdList;
int index = Array.IndexOf(pils, 0x501b); // サムネイル・データ
if (index == -1) {
Console.WriteLine("画像にサムネイルが含まれていません。");
} else {
// サムネイル・データの取得
PropertyItem pi = orig.PropertyItems[index];
byte[] jpgBytes = pi.Value;
// サムネイルの作成
Image thumbnail = (Image)imgconv.ConvertFrom(jpgBytes);
// サムネイルの保存
thumbnail.Save("tn_" + Path.GetFileName(jpg),
System.Drawing.Imaging.ImageFormat.Jpeg);
thumbnail.Dispose();
}
orig.Dispose();
}
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds + "ミリ秒");
// 出力例:619ミリ秒
}
}
// コンパイル方法:csc fasterthumbnail.cs
|
|
C#のサンプル・プログラム(fasterthumbnail.cs) |
|
' fasterthumbnail.vb
' FromStreamメソッドを使ったExifデータの読み込み
Imports System
Imports System.IO
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Diagnostics
Class FasterThumbnail
Shared Sub Main()
Dim dir As String = "C:\jpgs" ' 画像のあるディレクトリ
Dim jpgFiles As String() = Directory.GetFiles(dir, "*.jpg")
Dim imgconv As New ImageConverter()
Dim sw As Stopwatch = Stopwatch.StartNew()
For Each jpg As String In jpgFiles
Console.WriteLine(jpg)
Using fs As FileStream = File.OpenRead(jpg)
' 画像オブジェクトの作成
Dim orig As Image = Image.FromStream(fs, False, False)
Dim pils As Integer() = orig.PropertyIdList
Dim index As Integer = Array.IndexOf(pils, &H501B) ' サムネイル・データ
If index = -1 Then
Console.WriteLine("画像にサムネイルが含まれていません。")
Else
' サムネイル・データの取得
Dim pi As PropertyItem = orig.PropertyItems(index)
Dim jpgBytes As Byte() = pi.Value
' サムネイルの作成
Dim thumbnail As Image _
= CType(imgconv.ConvertFrom(jpgBytes), Image)
' サムネイルの保存
thumbnail.Save("tn_" + Path.GetFileName(jpg), _
System.Drawing.Imaging.ImageFormat.Jpeg)
thumbnail.Dispose()
End If
orig.Dispose()
End Using
Next
sw.Stop()
Console.WriteLine(sw.ElapsedMilliseconds & "ミリ秒")
' 出力例:619ミリ秒
End Sub
End Class
' コンパイル方法:vbc fasterthumbnail.vb
|
|
VBのサンプル・プログラム(fasterthumbnail.vb) |
|
筆者の環境では、このプログラムではさらに約15倍(最初のプログラムに比べて約86倍)高速にサムネイル画像を作成できた(もちろんこのような速度比は、対象となるJPEGファイルのサイズや構造、プログラムを実行した環境による)。
当然ながら、この最後のプログラムでは、Exif情報内にサムネイル画像が含まれていないJPEGファイルに対しては、サムネイル画像を作成できない。また、サムネイル画像を取り出すだけであるため、そのサイズを指定することもできない。
これに対して、最初の2つのプログラムではExif情報内にサムネイル画像が存在しない場合にも、それを作成することができる。これはGetThumbnailImageメソッドが本体画像からサムネイル画像を作成するためだ。また、GetThumbnailImageメソッドではサムネイル画像のサイズも指定できる。
|
generated by
|
|
Insider.NET 記事ランキング
本日
月間