#title(Magick.NETを使って、.NETがサポートしていない形式の画像を読み込む)

#navi(.NETプログラミング研究)

#contents

*Magick.NETを使って、.NETがサポートしていない形式の画像を読み込む [#na69d4e2]

.NET Frameworkは標準で、BMP、JPEG、GIF、PNGなど様々な形式の画像を扱うことができますが、それ以外の画像は表示することすら難しいです。このような.NET Frameworkでサポートされていない形式の画像を扱う方法の1つとして、「[[ImageMagick>http://www.imagemagick.org/index.php]]」を使う方法が考えられます。ImageMagickがサポートしている画像形式の数は100以上にのぼり、PDFやRAW画像にも対応しています(対応しているフォーマット一覧は、「[[ImageMagick: Formats>http://www.imagemagick.org/script/formats.php]]」)。

ImageMagickのWindows版には、コマンドラインツール(EXE)とDLLの2種類があります。.NET FrameworkでImageMagickの機能を使う場合は、これらを直接使用してももちろんよいのですが、専用のライブラリが幾つか公開されていますので、それらを使わせていただくとかなり楽ができます。

ImageMagickの.NET Framework用のライブラリには、「[[Magick.NET>http://magick.codeplex.com/]]」や「[[ImageMagick Application Wrapper>http://sourceforge.net/projects/imagemagickapp/]]」、「[[ImageMagick.NET>http://imagemagick.codeplex.com/]]」などがあります。ここでは、この中で一番メジャーと思われる「Magick.NET」を使ってみることにします。

**Magick.NETを使う準備をする [#x2788029]

残念ながらMagick.NETは今のところAlpha版しかありません。ライセンスは、Apache License 2.0のようです(詳しくは、「[[Magick.NET - License>http://magick.codeplex.com/license]]」)。

Magick.NETは、基本的には、ImageMagickを必要としません。しかし、Visual C++ 再頒布可能パッケージが必要です(.NET 4.0 は for Visual Studio 2012、.NET 2.0 は for Visual Studio 2008)。それ以外にも、扱う画像のフォーマットによっては、何らかのアプリケーションが必要な場合があります(別途アプリケーションが必要なフォーマットについては、「[[ImageMagick: Formats>http://www.imagemagick.org/script/formats.php]]」に記述があります)。

Magick.NETは、「[[Magick.NET - Download>http://magick.codeplex.com/releases/view/119491]]」からダウンロードすることができます。または、NuGetを使ってインストールすることもできます。

Magick.NETには様々なパッケージが用意されています。.NET 2.0と.NET 4.0がありますし、x64、x86、AnyCPUでも分かれています。さらに、「Q8」と「Q16」というものがあります。Q16は「16 bits-per-pixel(bpp)」の意味で、16bitの画像を劣化させることなく扱うことができるが、Q8よりもリソースは2倍必要になるということです(詳しくは、「[[ImageMagick: Install from Binary Distribution>http://www.imagemagick.org/script/binary-releases.php#windows]]」)。

私は、「Magick.NET-6.8.8.1001-Q16-x86-net40-client」を使ってみました。

NuGetを使わずにZIPをダウンロードした時は、アーカイブを展開すると、「Magick.NET-x86.dll」と「Magick.NET-x86.xml」(x64の場合は、「Magick.NET-x64.dll」と「Magick.NET-x64.xml」)の2つのファイルができます。このDLLをプロジェクトの参照設定に追加すれば、そのプロジェクトで使用できるようになります(詳しくは、「[[「○○○.dllを参照に追加します」の意味は?>http://dobon.net/vb/dotnet/help/addreference.html]]」)。

**ある形式の画像ファイルを別形式の画像ファイルにコンバートする [#o374fab9]

Magick.NETでは画像形式のコンバートが簡単にできますので、この機能を使用すれば、.NET Frameworkがサポートしていない形式の画像ファイルをサポートしている形式の画像ファイルに変換して、.NET Frameworkで扱うということができます。

例えば以下の例では、PSD形式の画像ファイル"C:\test\1.psd"を読み込んで、BMP形式の画像ファイル"C:\test\1.bmp"として保存してから、PictureBoxに表示しています。ちなみに"C:\test\1.bmp"がすでに存在している場合は、上書きされます。

#code(vbnet){{
'Adobe Photoshop PSD形式の画像ファイルを読み込む
Dim img As New ImageMagick.MagickImage("C:\test\1.psd")
'BMP形式で保存する
img.Write("C:\test\1.bmp")
'後始末
img.Dispose()

'PictureBox1に表示する
PictureBox1.ImageLocation = "C:\test\1.bmp"
}}

#code(csharp){{
//Adobe Photoshop PSD形式の画像ファイルを読み込む
ImageMagick.MagickImage img =
    new ImageMagick.MagickImage(@"C:\test\1.psd");
//BMP形式で保存する
img.Write(@"C:\test\1.bmp");
//後始末
img.Dispose();

//PictureBox1に表示する
PictureBox1.ImageLocation = @"C:\test\1.bmp";
}}

ものすごく簡単なコードですが、これだけでうまく行きました。

このコードでは保存する画像形式を指定していませんが、ファイル名で自動的に判断されるようです。もしファイルの拡張子をどの画像形式のものでもない文字列にした場合は、読み込んだ時の画像形式で保存されるようです。

もし保存する時の画像形式を明確にするなら、MagickImageのFormatプロパティに画像形式を設定すればよいようです。

#code(vbnet){{
'Adobe Photoshop PSD形式の画像ファイルを読み込む
Dim img As New ImageMagick.MagickImage("C:\test\1.psd")
'BMP形式で保存する
img.Format = ImageMagick.MagickFormat.Bmp
img.Write("C:\test\1.img")
'後始末
img.Dispose()
}}

#code(csharp){{
//Adobe Photoshop PSD形式の画像ファイルを読み込む
ImageMagick.MagickImage img =
    new ImageMagick.MagickImage(@"C:\test\1.psd");
//BMP形式で保存する
img.Format = ImageMagick.MagickFormat.Bmp;
img.Write(@"C:\test\1.img");
//後始末
img.Dispose();
}}

**読み込んだ画像をBitmapオブジェクトに変換する [#hbffa223]

MagickImageクラスのToBitmapメソッドを使えば、読み込んだ画像からSystem.Drawing.Bitmapオブジェクトを作成することもできます。

以下の例では、JPEG-2000形式の画像ファイル"C:\test\1.j2k"を読み込んでBitmapオブジェクトを作成し、PictureBoxに表示しています。

#code(vbnet){{
'JPEG 2000形式の画像ファイルを読み込む
Dim img As New ImageMagick.MagickImage("C:\test\1.j2k")
'Bitmapオブジェクトを作成する
Dim bmp As System.Drawing.Bitmap = img.ToBitmap()
'後始末
img.Dispose()

'PictureBox1に表示する
PictureBox1.Image = bmp
}}

#code(csharp){{
//JPEG 2000形式の画像ファイルを読み込む
ImageMagick.MagickImage img =
    new ImageMagick.MagickImage(@"C:\test\1.j2k");
//Bitmapオブジェクトを作成する
System.Drawing.Bitmap bmp = img.ToBitmap();
//後始末
img.Dispose();

//PictureBox1に表示する
PictureBox1.Image = bmp;
}}

このコードのようにToBitmapメソッドの引数に何も指定しないと、BMP形式のBitmapオブジェクトになります。もし別の形式にしたいのであれば、ToBitmapメソッドの引数に適当なSystem.Drawing.Imaging.ImageFormatオブジェクトを指定します。

以下の例では、PNG形式のBitmapオブジェクトを作成しています。

#code(vbnet){{
'JPEG 2000形式の画像ファイルを読み込む
Dim img As New ImageMagick.MagickImage("C:\test\1.j2k")
'PNG形式のBitmapオブジェクトを作成する
Dim bmp As System.Drawing.Bitmap = _
    img.ToBitmap(System.Drawing.Imaging.ImageFormat.Png)
'後始末
img.Dispose()
}}

#code(csharp){{
//JPEG 2000形式の画像ファイルを読み込む
ImageMagick.MagickImage img =
    new ImageMagick.MagickImage(@"C:\test\1.j2k");
//PNG形式のBitmapオブジェクトを作成する
System.Drawing.Bitmap bmp =
    img.ToBitmap(System.Drawing.Imaging.ImageFormat.Png);
//後始末
img.Dispose();
}}

なおMagickImage.ToBitmapSourceメソッドを使えば、System.Windows.Media.Imaging.BitmapSourceオブジェクトを作成することもできます。

**RAW画像を読み込む [#oaf9bd5c]

Magick.NETは、.RC2などのRAW画像を読み込むこともできます。ただしその場合は、「dcraw.exe」をMagick.NETのDLLと同じフォルダに入れる必要があります(「dcraw.exe」がないのにRAW画像を読み込もうとすると、ImageMagick.MagickBlobErrorExceptionがスローされます)。「dcraw.exe」は、「[[Windows Binary Release>http://www.imagemagick.org/script/binary-releases.php#windows]]」からダウンロードできるZIPファイルの中にあります(または、ImageMagickをインストールしても入手できるかもしれません)。

以下に例を示しますが、前の例と全く同じです。

#code(vbnet){{
'CR2(CanonデジタルカメラRAW画像形式)の画像ファイルを読み込む
Dim img As New ImageMagick.MagickImage("C:\test\1.cr2")
'Bitmapオブジェクトを作成する
Dim bmp As System.Drawing.Bitmap = img.ToBitmap()
'後始末
img.Dispose()

'PictureBox1に表示する
PictureBox1.Image = bmp
}}

#code(csharp){{
//CR2(CanonデジタルカメラRAW画像形式)の画像ファイルを読み込む
ImageMagick.MagickImage img =
    new ImageMagick.MagickImage(@"C:\test\1.cr2");
//Bitmapオブジェクトを作成する
System.Drawing.Bitmap bmp = img.ToBitmap();
//後始末
img.Dispose();

//PictureBox1に表示する
PictureBox1.Image = bmp;
}}

私が試した限りでは、RAW画像を読み込むのには結構な時間がかかりました。

**PDFファイルを読み込む [#g8e41e8b]

Magick.NETは、PDFやPostscript形式のファイルを読み込むこともできます。ただしこの場合は、[[Ghostscript>http://pages.cs.wisc.edu/~ghost/]]がインストールされている必要があります(Ghostscriptがインストールされていないのに読み込もうとすると、ImageMagick.MagickDelegateErrorExceptionがスローされます)。

Magick.NETはPDFファイルを作成することもできますが、この場合はGhostscriptが必要ありません。

Ghostscriptをインストールしたところで、今までと全く同じ方法でPDFファイルをPNGファイルに変換させてみました。

#code(vbnet){{
'PDFファイルを読み込む
Dim img As New ImageMagick.MagickImage("C:\test\1.pdf")
'PNG形式で保存する
img.Write("C:\test\1.png")
'後始末
img.Dispose()
}}

#code(csharp){{
//PDFファイルを読み込む
ImageMagick.MagickImage img =
    new ImageMagick.MagickImage(@"C:\test\1.pdf");
//PNG形式で保存する
img.Write(@"C:\test\1.png");
//後始末
img.Dispose();
}}

これは見事に成功し、PNGファイルができました。しかしPNGファイルの画像はPDFの1ページ目のみで、しかも字や絵がスカスカで、まともに読める状態ではありませんでした。

***解像度を指定する [#g4b160d3]

デフォルトでは解像度が72dpiとなるようで、かなり低く、そのためにスカスカになってしまったようです。MagickReadSettings.Densityプロパティを使って解像度を上げてあげれば、きれいになります。ただし、解像度を高くすると画像のサイズが大きくなり、読み込み時間も長くなります。

なおImageMagickの-densityオプションについては、「[[ImageMagick: Command-line Options>http://www.imagemagick.org/script/command-line-options.php#density]]」に詳しい説明があります。

#code(vbnet){{
'水平、垂直解像度(DPI)を指定する
Dim settings As New ImageMagick.MagickReadSettings()
settings.Density = New ImageMagick.MagickGeometry(300, 300)

'PDFファイルを読み込む
Dim img As New ImageMagick.MagickImage("C:\test\1.pdf", settings)
'PNG形式で保存する
img.Write("C:\test\1.png")
'後始末
img.Dispose()
}}

#code(csharp){{
//水平、垂直解像度(DPI)を指定する
ImageMagick.MagickReadSettings settings =
    new ImageMagick.MagickReadSettings();
settings.Density = new ImageMagick.MagickGeometry(300, 300);

//PDFファイルを読み込む
ImageMagick.MagickImage img =
    new ImageMagick.MagickImage(@"C:\test\1.pdf", settings);
//PNG形式で保存する
img.Write(@"C:\test\1.png");
//後始末
img.Dispose();
}}

***すべてのページを読み込む [#pa724c81]

PDFファイルのすべてのページを読み込むには、MagickImageの代わりにMagickImageCollectionを使ってPDFファイルを読み込みます。MagickImageCollectionはその名の通りMagickImageのコレクションで、PDFのすべてのページがコレクションに追加されます。

以下の例では、PDFファイル"C:\test\1.pdf"を読み込んで、すべてのページを1枚ずつPNGファイルとして保存しています。

#code(vbnet){{
'水平、垂直解像度(DPI)を指定する
Dim settings As New ImageMagick.MagickReadSettings()
settings.Density = New ImageMagick.MagickGeometry(300, 300)

'PDFを読み込んで、MagickImageCollectionオブジェクトを作成
Dim imgs As New ImageMagick.MagickImageCollection("C:\test\1.pdf", settings)

'1ページずつMagickImageオブジェクトを取得する
For i As Integer = 0 To imgs.Count - 1
    '1ページずつPNGファイルとして保存する
    Dim img As ImageMagick.MagickImage = imgs(i)
    img.Write(String.Format("C:\test\page-{0}.png", i + 1))
Next

'後始末
imgs.Dispose()
}}

#code(csharp){{
//水平、垂直解像度(DPI)を指定する
ImageMagick.MagickReadSettings settings =
    new ImageMagick.MagickReadSettings();
settings.Density = new ImageMagick.MagickGeometry(300, 300);

//PDFを読み込んで、MagickImageCollectionオブジェクトを作成
ImageMagick.MagickImageCollection imgs =
    new ImageMagick.MagickImageCollection(@"C:\test\1.pdf", settings);

//1ページずつMagickImageオブジェクトを取得する
for (int i = 0; i < imgs.Count; i++)
{
    //1ページずつPNGファイルとして保存する
    ImageMagick.MagickImage img = imgs[i];
    img.Write(string.Format(@"C:\test\page-{0}.png", i + 1));
}

//後始末
imgs.Dispose();
}}

***もっと簡単にすべてのページを保存する [#h0201f51]

実はMagickImageCollection.Writeメソッドを使うと、一発ですべてのページを別々の画像ファイルに保存できます。

例えば以下の例のようにMagickImageCollection.Writeメソッドに"C:\test\1.png"という文字列を渡すと、"C:\test\1-0.png"、"C:\test\1-1.png"...のような名前のファイルがページ数分作成されます。

#code(vbnet){{
'水平、垂直解像度(DPI)を指定する
Dim settings As New ImageMagick.MagickReadSettings()
settings.Density = New ImageMagick.MagickGeometry(300, 300)

'PDFを読み込んで、MagickImageCollectionオブジェクトを作成
Dim imgs As New ImageMagick.MagickImageCollection("C:\test\1.pdf", settings)
'すべてのページを1枚ずつPNGファイルに保存する
imgs.Write("C:\test\1.png")

'後始末
imgs.Dispose()
}}

#code(csharp){{
//水平、垂直解像度(DPI)を指定する
ImageMagick.MagickReadSettings settings =
    new ImageMagick.MagickReadSettings();
settings.Density = new ImageMagick.MagickGeometry(300, 300);

//PDFを読み込んで、MagickImageCollectionオブジェクトを作成
ImageMagick.MagickImageCollection imgs =
    new ImageMagick.MagickImageCollection(@"C:\test\1.pdf", settings);
//すべてのページを1枚ずつPNGファイルに保存する
imgs.Write(@"C:\test\1.png");

//後始末
imgs.Dispose();
}}

***すべてのページを1枚の画像に結合させる [#c2219e05]

MagickImageCollection.AppendVerticallyメソッドを使うと、すべてのページを縦に連結して1つの画像を作成できます。また、AppendHorizontallyメソッドを使うと、横に結合します。

#code(vbnet){{
'PDFを読み込む
Dim imgs As New ImageMagick.MagickImageCollection("C:\test\1.pdf")

'すべてのページを縦方向につなげた画像を作成する
Dim vImg As ImageMagick.MagickImage = imgs.AppendVertically()
'保存する
vImg.Write("C:\test\v.png")

'すべてのページを横方向につなげた画像を作成する
Dim hImg As ImageMagick.MagickImage = imgs.AppendHorizontally()
'保存する
hImg.Write("C:\test\h.png")

'後始末
vImg.Dispose()
hImg.Dispose()
imgs.Dispose()
}}

#code(csharp){{
//PDFを読み込む
ImageMagick.MagickImageCollection imgs =
    new ImageMagick.MagickImageCollection(@"C:\test\1.pdf");

//すべてのページを縦方向につなげた画像を作成する
ImageMagick.MagickImage vImg = imgs.AppendVertically();
//保存する
vImg.Write(@"C:\test\v.png");

//すべてのページを横方向につなげた画像を作成する
ImageMagick.MagickImage hImg = imgs.AppendHorizontally();
//保存する
hImg.Write(@"C:\test\h.png");

//後始末
vImg.Dispose();
hImg.Dispose();
imgs.Dispose();
}}

***読み込むページと枚数を指定する [#y176bdde]

MagickReadSettingsのFrameIndexとFrameCountプロパティを使うと、読み込むページと枚数を指定できます。FrameIndexプロパティには、読み込むページのインデックスを指定します。1ページ目から読み込む場合は、0です。FrameCountプロパティには、読み込む枚数を指定します。

以下の例では、PDFファイルの3ページ目だけを読み込んで、PictureBoxに表示しています。

#code(vbnet){{
Dim settings As New ImageMagick.MagickReadSettings()
'水平、垂直解像度(DPI)を指定する
settings.Density = New ImageMagick.MagickGeometry(300, 300)
'3ページ目から読み取る
settings.FrameIndex = 2
'1ページだけ読み取る
settings.FrameCount = 1

'PDFを読み込む
Dim imgs As New ImageMagick.MagickImageCollection("C:\test\1.pdf", settings)

'PictureBox1に表示する
PictureBox1.Image = imgs(0).ToBitmap()

'後始末
imgs.Dispose()
}}

#code(csharp){{
ImageMagick.MagickReadSettings settings =
    new ImageMagick.MagickReadSettings();
//水平、垂直解像度(DPI)を指定する
settings.Density = new ImageMagick.MagickGeometry(300, 300);
//3ページ目から読み取る
settings.FrameIndex = 2;
//1ページだけ読み取る
settings.FrameCount = 1;

//PDFを読み込む
ImageMagick.MagickImageCollection imgs =
    new ImageMagick.MagickImageCollection(@"C:\test\1.pdf", settings);

//PictureBox1に表示する
PictureBox1.Image = imgs[0].ToBitmap();

//後始末
imgs.Dispose();
}}

**コメント [#ee7a59ab]
#comment

//これより下は編集しないでください
#pageinfo([[:Category/.NET]] [[:Category/ASP.NET]],2014-04-28 (月) 01:50:24,DOBON!,2014-04-28 (月) 01:50:24,DOBON!)

[ トップ ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]