サムネイル表示が出来る画像ファイルの種類をImageMagicで拡大したいと思います。
パッケージの追加
.NETむけのImageMagickのパッケージのMagic.netをプロジェクトに追加します。
dotnet add package Magick.NET-Q8-AnyCPU
dotnet add package Magick.NET.SystemWindowsMedia
ソースコード
Helpers\ImageMagicHelper.cs
using System.IO;
using System.Windows.Media.Imaging;
using ImageMagick;
namespace WpfFileManager.Helpers;
static class ImageMagicHelper
{
static readonly HashSet<string> SupportedExtensions_Image =
[
// 一般画像
".png",
".jpg",
".jpeg",
".bmp",
".gif",
".tif",
".tiff",
// 次世代フォーマット
".webp",
".avif",
".heic",
".heif",
".jp2",
".jxl",
];
static readonly HashSet<string> SupportedExtensions_Container =
[
// レイヤー画像
".psd",
".xcf",
".ora",
".kra",
// ベクター・ドキュメント
".svg",
".pdf",
// RAW(環境依存)
".cr2",
".cr3",
".nef",
".arw",
".dng",
".raf"
];
static readonly HashSet<string> SupportedExtensions_Movie =
[
// 動画
".mp4",
".m4v",
".mov",
".webm",
".mkv",
".avi",
// 環境依存
".wmv",
".flv",
".ts",
".mts",
".m2ts",
".3gp"
];
// サムネイル画像をロード
public static BitmapSource LoadThumbImage(string file)
{
BitmapImage bmp = new();
using var image = new MagickImage(file);
// サムネイルサイズ
image.Resize(256, 256);
image.Format = MagickFormat.Png;
using var ms = new MemoryStream();
image.Write(ms);
ms.Position = 0;
bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.StreamSource = ms;
bmp.EndInit();
bmp.Freeze();
return bmp;
}
// 対応拡張子判定(画像系)
public static bool IsSupportedImage(string file)
{
var ext = Path.GetExtension(file).ToLowerInvariant();
return SupportedExtensions_Image.Contains(ext);
}
// 対応拡張子判定(コンテナ系)
public static bool IsSupportedContainer(string file)
{
var ext = Path.GetExtension(file).ToLowerInvariant();
return SupportedExtensions_Container.Contains(ext);
}
// 対応拡張子判定(動画系)
public static bool IsSupportedMovie(string file)
{
var ext = Path.GetExtension(file).ToLowerInvariant();
return SupportedExtensions_Movie.Contains(ext);
}
// 対応拡張子判定(全体)
public static bool IsSupported(string file)
{
string ext = Path.GetExtension(file).ToLowerInvariant();
bool result = false;
result = SupportedExtensions_Image.Contains(ext);
if (result) return true;
result = SupportedExtensions_Container.Contains(ext);
if (result) return true;
result = SupportedExtensions_Movie.Contains(ext);
if (result) return true;
return false;
}
}
画像ロードの呼び出しプログラムをImageMagicHelper.LoadThumbImage(file);に差し替えます。
FileItem.cs
static private BitmapSource? LoadImage(string file)
{
/*
string[] extensions = [ ".jpg", ".jpeg", ".png", ".bmp", ".gif" ];
if (!Array.Exists(extensions, ext => file.EndsWith(ext, StringComparison.OrdinalIgnoreCase)))
{
return null;
}
*/
if (Directory.Exists(file)) return null;
string cachePath = CachePath(file);
if (File.Exists(cachePath))
{
BitmapImage cthumb = new ();
cthumb.BeginInit();
cthumb.UriSource = new Uri(cachePath);
cthumb.DecodePixelWidth = 256; // サムネイルサイズ
cthumb.CacheOption = BitmapCacheOption.OnLoad;
cthumb.EndInit();
cthumb.Freeze(); // UIスレッド外でも使用可
return cthumb;
}
try
{
/*
BitmapImage thumb = new ();
thumb.BeginInit();
thumb.UriSource = new Uri(file);
thumb.DecodePixelWidth = 256; // サムネイルサイズ
thumb.CacheOption = BitmapCacheOption.OnLoad;
thumb.EndInit();
thumb.Freeze(); // UIスレッド外でも使用可
*/
if (ImageMagicHelper.IsSupported(file))
{
var thumb = ImageMagicHelper.LoadThumbImage(file);
SaveThumbnail(thumb, cachePath);
return thumb;
}
else
{
return null;
}
}
catch
{
// 壊れた画像などは無視
return null;
}
}
感想
比較的簡単に複数の画像ファイルに対応出来ました。
サムネイル表示時に画像なのか動画なのか見分けがつきにくいので、対策を考えてみいたいと思いました。
追記20260203
※追記
サムネイル生成に Magick.NET(ImageMagick) を利用していましたが、
実際にアプリを操作して検証を重ねた結果、
ディレクトリ切り替えやサムネイル再生成を何度も繰り返すと、UI が数秒固まる現象が確認されました。
例外は発生せず、初回や少数回の実行では問題が出ないため原因の切り分けが難しかったのですが、
Magick.NET を完全に外すことでこの症状が再現しなくなることを確認できました。
現在は、
JPEG / PNG は WPF 標準の BitmapImage
動画は OpenCV
を使用し、Magick.NET は常用ルートから外しています。
ちなみに動画をOpenCVにした理由はMagick.Netは動画を全て読み込んでいるかの如く(未確認)、
ものすごい量のデータとそれに伴う時間がかかることから、OpenCVで1フレームだけ読み込むコードに変えています。

大本のImageMagickは相当枯れたアプリだとは思うので、.NETやC#の相性か、はたまた私の環境原因なのか、
とりあえず状況が変わるまで、切り離す方向にします。
記事を書いたサンプルコードならきちんと動作するのですけどね。
PSD や XCF などの特殊フォーマットについては、未定です。
個人的にはここが一番欲しいところで、代替を探したいのですが、
Windows環境(.NET)では中々変わりが見つかりません。
本家ImageMagickやGIMPのバッチモードなどを使い、
別タスクでキャッシュファイルを作る方法もありますが、
使い勝手か悪くなるので、どうするか検討中です。
エクスプローラーライクのファイルマネージャと画像のサムネイル表示は何度も挑戦していますが、
UIのパフォーマンスの調整の段階で躓きます。
前段でも書きましたが、エラーや例外が発生しないが、動作が遅くなる現象に遭遇すると、
デバックトレースでも要因が見つけることが出来ず、切り分けしながら要因を探すはめになり、
中々楽しい作業になります。
WindowsのエクスプローラーやmacOSのファインダーなど、標準アプリの安定度やパフォーマンスは
さすがプロの仕事だなぁと感心してしまいます。


コメント