teratail header banner
teratail header banner
質問するログイン新規登録
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

2回答

831閲覧

BitmapImage でBITMAPのボトムアップ/トップダウンを判別したい。

yukitad

総合スコア14

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

0クリップ

投稿2023/09/15 09:15

編集2023/09/15 10:33

0

0

前提

旧アプリがc++でMFCで作られてました
新アプリは、c# WPFで作られているのですが、旧アプリではあったBMPファイルの読込機能が追加されることになりました
同等の機能(データは上から取得する)必要な為、データの並びを判別しなければいけません

実現したいこと

System.Windows.Media.Imaging.BitmapImage
でBITMAPのボトムアップ/トップダウンを判別したい。

CImage::GetPitch
のような機能はないのでしょうか?

試したこと

旧アプリではgetpitchで判別してました
bitmapsourceクラス関連を調べていますが、相応の機能が見つかりませんでした

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2023/09/15 10:44

BITMAPのボトムアップ/トップダウンとはなんのことを言ってるんでしょうか。 また、それを判定してなにをやりたいのでしょう。
yukitad

2023/09/16 05:44

説明不足すみません と補足説明ありがとうございます
guest

回答2

0

バイナリーで読み込んで、BITMAPINFOHEADER部分のbiHeightで判断すればいいのではないでしょうか
ビットマップファイルをバイナリで開く」こちらが参考になりませんか?

投稿2023/09/15 11:01

YAmaGNZ

総合スコア10674

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yukitad

2023/09/16 05:42

バイナリで読み込むしかなさそうなんですね…。ありがとうございます
guest

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
KOZ6.0

総合スコア2736

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yukitad

2023/09/16 05:38

丁寧に実現方法と時間測定までして頂きありがとうございました 参考にさせていただきます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問