WPF サムネイル表示アプリ試作メモ3「ImageMagicによる対応画像の拡大」

コンピュータ

サムネイル表示が出来る画像ファイルの種類を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;
        }
    }

感想

比較的簡単に複数の画像ファイルに対応出来ました。
サムネイル表示時に画像なのか動画なのか見分けがつきにくいので、対策を考えてみいたいと思いました。

コメント