【C#】非同期にフォルダ内の画像の解像度を取得する方法


この記事はプロモーションを含みます。

C#でフォルダ内の画像解像度を非同期に取得する方法を紹介します。
UIスレッドをブロックせず、スムーズに処理を進める技術を解説します。

はじめに

C#でフォルダ内に保存された画像の解像度を取得するタスクは簡単に実装できますが、大量の画像を処理する場合やGUIアプリケーションで行う場合、UIがブロックされてしまうことがあります。
この問題を回避するためには、非同期処理を活用することが非常に効果的です。
この記事では、フォルダ内の画像ファイルを非同期に処理し、解像度を取得する方法について解説します。

UIロックの問題

画像の解像度を取得するには、通常、Image.FromFileメソッドを使用して画像を読み込む必要があります。しかし、この操作はI/O操作を伴い、処理が同期的に行われるため、特に大量の画像を処理する場合、UIスレッドがブロックされてしまいます。これにより、ユーザーは操作を行うことができなくなり、アプリケーションがフリーズしたように感じることがあります。

非同期処理を使ってUIのロックを回避

この問題を解決するために、非同期処理を導入することができます。
C#では、asyncおよびawaitキーワードを使用して非同期メソッドを作成することで、I/O処理をバックグラウンドで行うことができます。これにより、UIスレッドはブロックされることなく、並行して他の処理を実行することができます。

特に、Task.Runを使用して画像の解像度取得処理を非同期タスクとして実行することが有効です。
これにより、フォルダ内のすべての画像を並行して処理し、UIがスムーズに動作し続けるようになります。

非同期処理によるメリット

非同期処理を導入することにより、アプリケーションのパフォーマンスが向上し、ユーザーの操作感が大幅に改善されます。特に、GUIアプリケーションで大量のデータを扱う場合、UIスレッドがロックされることなく、他の操作を行いながらバックグラウンドで処理を進めることができます。

  • スムーズな操作感:UIがフリーズせず、ユーザーは他の操作を行うことができます。
  • リソースの最適化:非同期処理を使うことで、CPUやメモリリソースを効率的に使用できます。
  • 並行処理の実現:Task.Runを使うことで、複数の画像を並行して処理でき、全体の処理時間が短縮されます。

実装方法とソースコード

まず、フォルダ内のすべての画像ファイルを取得し、それぞれのファイルに対して非同期に解像度を取得するタスクを実行します。このタスクはバックグラウンドで画像を読み込み、解像度を取得します。すべての画像の解像度を取得した後は、結果をUIに表示します。
以下はソースコードです。

namespace WinFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            // 画像が保存されているフォルダのパス
            string folderPath = textBox1.Text;

            // フォルダ内の全てのファイルを取得
            string[] allFiles = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories);

            // リッチテキストボックスをクリア
            richTextBox1.Clear();

            foreach (string imageFile in allFiles)
            {
                // 画像ファイルが画像形式かどうかを確認
                if (IsImageFile(imageFile))
                {
                    // 非同期で画像の解像度を取得
                    await Task.Run(() =>
                    {
                        string output = GetImageResolution(imageFile);
                        AppendTextToRichTextBox(output);
                    });
                }
            }
        }

        // 画像ファイルかどうかを判定するメソッド
        private static bool IsImageFile(string filePath)
        {
            string[] imageExtensions = [ ".jpg", ".jpeg", ".png", ".bmp" ];
            string extension = Path.GetExtension(filePath).ToLower();
            return Array.Exists(imageExtensions, ext => ext == extension);
        }

        // 画像の解像度を取得するメソッド
        private static string GetImageResolution(string imageFile)
        {
            string output = "";
            try
            {
                using Image img = Image.FromFile(imageFile);
                output = $"ファイル:{imageFile}\n幅:{img.Width} px, 高さ:{img.Height} px\n";
            }
            catch(Exception)
            {
                output = $"ファイル:{imageFile}\n解像度を取得できません。\n";
            }
            return output;
        }

        // リッチテキストボックスに逐次的にテキストを追加するメソッド
        private void AppendTextToRichTextBox(string text)
        {
            // UIスレッドでリッチテキストボックスを更新
            if (richTextBox1.InvokeRequired)
            {
                richTextBox1.Invoke(new Action<string>(AppendTextToRichTextBox), text);
            }
            else
            {
                richTextBox1.AppendText(text);
                richTextBox1.ScrollToCaret();
            }
        }
    }
}

上記コードを実行し、画像を読み込むと以下のような結果を取得出来ます。
解像度を取得出来ない場合は「解像度を取得できません。」と出力します。

ファイル:C:\Workspace\ダミー.jpg
解像度を取得できません。
ファイル:C:\Workspace\画像1.bmp
幅:1280 px, 高さ:720 px
ファイル:C:\Workspace\画像2.jpeg
幅:1920 px, 高さ:1080 px
ファイル:C:\Workspace\画像3.jpg
幅:3840 px, 高さ:2160 px

まとめ

画像の解像度を取得するタスクは、シンプルな処理に見えますが、大量の画像を処理する場合やGUIアプリケーションで行う場合はUIスレッドがロックされる問題が発生します。この問題を解決するために、非同期処理を活用することで、UIをブロックせずにスムーズに動作させることができます。

C#での非同期処理は、asyncとawaitを使用して簡単に実装でき、Task.Runを使ってバックグラウンドでの処理を実行することで、効率的な処理が可能になります。これにより、ユーザーに快適な操作感を提供できるアプリケーションを作成することができます。

コメント

タイトルとURLをコピーしました