C#のWPFで4K画像ファイルの読み込み~デコード速度を計測。(BMP,PNG,NTFS圧縮)

コンピュータ

C#で3840×2180で32bit(BGRA)のPNGとBMP形式の画像ファイルを用意しBitmapオブジェクトの作成までの速度を計測してみます。
BMPに関してはNTFS圧縮したものも計測してみます。

ファイルサイズ

各ファイルのサイズは以下の通り

PNG:3.18 MB
BMP:31.6 MB
BMP(NTFS圧縮):7.93 MB

速度計測プログラムソース

using System.Diagnostics;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;

class Program2
{
    static BitmapSource LoadImage(string imgPath)
    {
        using FileStream fs = new (imgPath, FileMode.Open, FileAccess.Read);
        const int dpi = 96;

        Stopwatch sw = new();

        using MemoryStream ms = new();

        sw.Start();
        fs.CopyTo(ms);
        ms.Seek(0, SeekOrigin.Begin);
        sw.Stop();
        Console.WriteLine("Read:{0}ms", sw.ElapsedMilliseconds);

        sw.Restart();
        BitmapSource bs = BitmapFrame.Create(ms);

        int stride = (bs.PixelWidth * bs.Format.BitsPerPixel + 7) / 8;
        byte[] pixels = new byte[stride * bs.PixelHeight];
        bs.CopyPixels(pixels, stride, 0);

        bs = BitmapImage.Create(bs.PixelWidth, bs.PixelHeight, dpi, dpi, PixelFormats.Bgra32, null, pixels, stride);
        bs.Freeze();
        sw.Stop();
        Console.WriteLine("Decode:{0}ms", sw.ElapsedMilliseconds);
        
        ms.SetLength(0);

        return bs;
    }
    static void TestLoadImage()
    {
        string imgPath = @"f:/tmp/sample.png";
        Console.WriteLine("PNGファイル");
        var _ = LoadImage(imgPath);

        Console.WriteLine("BMPファイル");
        imgPath = @"f:/tmp/sample.bmp";
        _ = LoadImage(imgPath);
        
        Console.WriteLine("BMPファイル(NTFS圧縮)");
        imgPath = @"f:/tmp_ntfs_compress/sample.bmp";
        _ = LoadImage(imgPath);
    }
    public static void Main()
    {
        TestLoadImage();
    }
}

USB-SSDの速度計測結果

PNGファイル
Read:35ms
Decode:122ms
BMPファイル
Read:67ms
Decode:30ms
BMPファイル(NTFS圧縮)
Read:191ms
Decode:30ms

FileStreamからMemoryStreamでRead、MemoryStreamからBitmapSourceを作成している部分をDecodeとしています。
Read部分はファイルサイズが一番小さいPNG形式が35msと一番速いですが、Decodeは122msで一番遅い結果となりました。
BMPファイルはReadが67ms、NTFS圧縮で191ms、Decodeは30ms、NTFS圧縮も30msという結果になりした。

読み込み~デコードまでの速度は以下のような順番となりました。
BMP<PNG<<BMP(NTFS圧縮)

ファイルサイズ
PNG<BMP(NTFS圧縮)<<BMP

HDDの速度計測結果

PNGファイル
Read:29ms
Decode:139ms
BMPファイル
Read:195ms
Decode:31ms
BMPファイル(NTFS圧縮)
Read:1767ms
Decode:31ms

感想

WPFで画像を表示するプログラムを作成しており、画像ファイルの読み込み~表示までのレスポンスアップの方法を模索しています。
表示する画像ファイルの解像度はいろいろですが、表示するディスプレイサイズは3840×2180を想定しており、そのサイズに加工した画像ファイルをあらかじめ保存しておく場合、容量と速度のバランスが良いのはどれかテストしてみました。

デコードが速いのはBMPですがファイルサイズが大きいです。
ファイルサイズが小さいのはPNGですがデコードが遅い。
NTFS圧縮のBMPファイルはファイルサイズは小さくなりますが、読み込みが遅くストレージの性能さが顕著に表れます。
ちなみに2回目以降はディスクキャッシュが効くおかげかNTFS圧縮したBMPも無圧縮並みの速度になります。

結果としてはどれも一長一短といった感じです。

ただ、一般に公開されているアプリケーションでは採用しずらいですが、SSDの速度をつかって無圧縮のBMPファイルでハイレスポンスな画像表示アプリケーションを作成するのも面白そうな感じがします。

追記:
jpgファイルも気になったので確認します。

jpgファイルのサイズ:
1.28 MB

JPGファイル
Read:3ms
Decode:1033ms

画像ファイルの内容と実行しているPCがPNGやBMPファイルとは異なるので単純には比較できませんが、デコードに時間がかかっている感じです。ファイルサイズは一番小さく、デコードは一番遅いという結果になりました。

ただ、JPGを実行しているPCはエントリークラスのCPUが搭載されたノートパソコンですので、GPUなどもCPU内蔵ですので、スペックの高いPCであれば別の結果が出るかもしれません。

画像の保存方法として可逆圧縮でファイルサイズを小さくしながら劣化しないPNGファイルかより圧縮率の高いWebPが考えられます。ただ閲覧を考えると高解像度な画像ファイルだとしても表示用のディスプレイサイズで頭打ちになるため、閲覧用に最適化した解像度の画像ファイルを用意する方法が考えらます。

聞くところによると可逆圧縮のWebPはPNGと比べてエンコードが遅いですが、ファイルサイズは小さくデコードは速い傾向にあるらしいので、ベストな保存形式だと考えらます。ただWindows11のエクスプローラーでサムネイル表示に対応していない点でPNGの方が扱いやすい感じがします。

コメント