C#でJpegとPNGファイルから幅と高さを取得

C# コンピュータ
C#
多数の画像ファイルから幅と高さを取得する必要があり、なるべく短い時間で取得できるように試作してみました。
C#で画像の高さや幅を取得する方法として、画像ファイルからSystem.Drawing.Bitmapなどのオブジェクトを生成し、オブジェクトの高さや幅のプロパティを参照することで実現出来ます。ただ、この方法の場合オブジェクトの生成にコストが生じます。欲しい情報は幅と高さだけなのに、オブジェクト化するために画像全体を収めるメモリを確保必要があったりしますので、PCのリソース的にやさしくない処理になります。それでも、少数の画像を扱う分には無視しても問題ないですが、多量の画像ファイルをを扱う場合処理時間などで大きな差が生じます。
画像ファイルの内部は基本バイナリデータ(SVGとかはテキスト)ですが、どの画像フォーマットでも大概、幅や高さの数値情報が所定のアドレス記録されています。その数値をピンポイントで読み込む処理を行うことで画像の幅と高さを取得するプログラムとなります。

ソースコード

public class Program1
{
    static public void Main()
    {
        var buf = new byte[0xffff];
        int width = 0;
        int height = 0;

        string path = @"F:\csharp\ImgView2\00201.png";
        path = @"F:\csharp\ImgView2\00201.png";
        using var fs = new FileStream(path, FileMode.Open, FileAccess.Read);

        fs.Read(buf, 0, buf.Length);

        // PNG
        if (buf.Take(8).SequenceEqual(new byte[]{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,}))
        {
            var w = buf.Skip(8+8+0).Take(4).Reverse().ToArray();
            var h = buf.Skip(8+8+4).Take(4).Reverse().ToArray();
            width = BitConverter.ToInt32(w);
            height = BitConverter.ToInt32(h);
            Console.WriteLine($"PNG: Width:{width} Height:{height}");
        }

        // JPEG
        if (buf.Take(2).SequenceEqual(new byte[] { 0xff, 0xd8, }))
        {
            var i = buf.Select((x,i) => new { index = i, value = buf.Skip(i).Take(2)})
                .Where(x => x.value.SequenceEqual(new byte[] { 0xff, 0xc0,} ))
                .Select(x => x.index)
                .DefaultIfEmpty(-1)
                .First();
            if (i >= 0)
            {
                var w = buf.Skip(i+2+5).Take(2).Reverse().ToArray();    
                var h = buf.Skip(i+2+3).Take(2).Reverse().ToArray();    
                width = (int)BitConverter.ToInt16(w);
                height = (int)BitConverter.ToInt16(h);
                Console.WriteLine($"JPEG: Width:{width} Height:{height}");
            }
        }
    }
}

結果

PNG: Width:846 Height:1200
いろいろ適当ですがPNGとJpegの数値を取得できました。
BitConverter()でbyte配列から数値に変換していますが、リトルエンディアンで決め打ちしています。
byte[]配列をLINQで操作できることを初めて知りましたが結構便利です。
追記
Wikiなどで画像フォーマットの情報を調べ、画像ファイルの中で幅と高さの数値が書き込まれた場所を決め打ちして呼び出しています。特定の画像形式でテストを沢山すれば実用的なプログラムを組めるかもしれませんが、世の中に無数に存在する画像フォーマットに対応するのは、大変な労力ですので誰かが作ってくれたライブラリを利用しましょう。
Magick.net
C#でMagick.NETを使って画像ファイルの幅と高さを取得する。
画像ファイルの幅と高さを取得する方法として、Sysmte.Drawing.Bitmapのオブジェクトを生成し、プロパティのWidthやHeightを参照すれば良いのですが、ファイルサイズが大きな画像ファイルが多量にある場合、毎回Bitmap...

コメント