前提
旧アプリがc++でMFCで作られてました
新アプリは、c# WPFで作られているのですが、旧アプリではあったBMPファイルの読込機能が追加されることになりました
同等の機能(データは上から取得する)必要な為、データの並びを判別しなければいけません
実現したいこと
System.Windows.Media.Imaging.BitmapImage
でBITMAPのボトムアップ/トップダウンを判別したい。
CImage::GetPitch
のような機能はないのでしょうか?
試したこと
旧アプリではgetpitchで判別してました
bitmapsourceクラス関連を調べていますが、相応の機能が見つかりませんでした
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/09/15 11:52

回答2件
0
バイナリーで読み込んで、BITMAPINFOHEADER部分のbiHeightで判断すればいいのではないでしょうか
「ビットマップファイルをバイナリで開く」こちらが参考になりませんか?
投稿2023/09/15 11:01
総合スコア10674
0
ベストアンサー
こんなもんでしょうか?
csharp
1using System; 2using System.Diagnostics; 3using System.IO; 4using System.Runtime.InteropServices; 5using System.Windows.Media.Imaging; 6 7public static class BitmapImageHelper 8{ 9 [StructLayout(LayoutKind.Sequential, Pack = 2)] 10 private struct BITMAPFILEHEADER 11 { 12 public ushort bfType; 13 public uint bfSize; 14 public ushort bfReserved1; 15 public ushort bfReserved2; 16 public uint bfOffBits; 17 } 18 19 [StructLayout(LayoutKind.Sequential)] 20 private struct BITMAPINFOHEADER 21 { 22 public uint biSize; 23 public int biWidth; 24 public int biHeight; 25 public ushort biPlanes; 26 public ushort biBitCount; 27 public uint biCompression; 28 public uint biSizeImage; 29 public int biXPelsPerMeter; 30 public int biYPelsPerMeter; 31 public uint biClrUsed; 32 public uint biClrImportant; 33 } 34 35 public enum BitmapDirection 36 { 37 TopDown, BottomUp 38 } 39 40 public static BitmapImage BitmapImageFromFile( 41 string fileName, 42 out BitmapDirection direction) { 43 byte[] bytes = File.ReadAllBytes(fileName); 44 direction = GetBitmapDirection(bytes); 45 using (MemoryStream mem = new MemoryStream(bytes)) { 46 BitmapImage bitmap = new BitmapImage(); 47 bitmap.BeginInit(); 48 bitmap.StreamSource = mem; 49 bitmap.CacheOption = BitmapCacheOption.OnLoad; 50 bitmap.EndInit(); 51 bitmap.Freeze(); 52 return bitmap; 53 } 54 } 55 56 public static BitmapDirection GetBitmapDirection(byte[] bytes) { 57 int offset = Marshal.SizeOf(typeof(BITMAPFILEHEADER)); 58 int size = Marshal.SizeOf(typeof(BITMAPINFOHEADER)); 59 IntPtr ptr = Marshal.AllocCoTaskMem(size); 60 try { 61 Marshal.Copy(bytes, offset, ptr, size); 62 BITMAPINFOHEADER infoHeader = Marshal.PtrToStructure<BITMAPINFOHEADER>(ptr); 63 return infoHeader.biHeight > 0 ? BitmapDirection.BottomUp 64 : BitmapDirection.TopDown; 65 } finally { 66 Marshal.FreeCoTaskMem(ptr); 67 } 68 } 69}
Unsafe 版とSpan版を作って比較してみました。
csharp
1// Unsafe 版 2public static unsafe BitmapDirection UnsafeGetBitmapDirection(byte[] bytes) { 3 fixed (byte* lpFileHeader = bytes) { 4 BITMAPINFOHEADER* lpInfoHeader = 5 (BITMAPINFOHEADER*)(lpFileHeader + sizeof(BITMAPFILEHEADER)); 6 return lpInfoHeader->biHeight > 0 ? BitmapDirection.BottomUp 7 : BitmapDirection.TopDown; 8 } 9} 10 11// Span 版 12public static BitmapDirection SpanGetBitmapDirection(byte[] bytes) { 13 int offset = Marshal.SizeOf(typeof(BITMAPFILEHEADER)); 14 int size = Marshal.SizeOf(typeof(BITMAPINFOHEADER)); 15 Span<byte> span = new Span<byte>(bytes, offset, size); 16 BITMAPINFOHEADER infoHeader = MemoryMarshal.Read<BITMAPINFOHEADER>(span); 17 return infoHeader.biHeight > 0 ? BitmapDirection.BottomUp 18 : BitmapDirection.TopDown; 19} 20 21public static void TryGetBitmapDirection(string fileName) { 22 byte[] bytes = File.ReadAllBytes(fileName); 23 Watch("GetBitmapDirection", () => { GetBitmapDirection(bytes); }); 24 Watch("UnsafeGetBitmapDirection", () => { UnsafeGetBitmapDirection(bytes); }); 25 Watch("SpanGetBitmapDirection", () => { SpanGetBitmapDirection(bytes); }); 26} 27 28public static void Watch(string message, Action action) { 29 Stopwatch sw = new Stopwatch(); 30 sw.Start(); 31 for (int i = 0; i < 100000; i++) { 32 action.Invoke(); 33 } 34 sw.Stop(); 35 Console.WriteLine($"{message} {sw.ElapsedMilliseconds}ms"); 36} 37 38結果 39GetBitmapDirection 61ms 40UnsafeGetBitmapDirection 1ms 41SpanGetBitmapDirection 12ms
Span も速いですが、やはり Unsafe は速かった。
投稿2023/09/15 14:09
編集2023/09/16 03:18総合スコア2736
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。