午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

WPFとVB.NETで表示した画像をクリックした場所の色を取得はややこしい(後編)

前回の画像をクリックした場所の色を取得の続き、終わったと思ったら終わってなかった

gogowaten.hatenablog.com

 
WPFVB.NETで表示した画像をクリックした場所の色を取得はややこしい ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/13952774.html
のつづき
 
画像とWindowsのDpiが違うと画像の上にあるマウスカーソルから取得できる位置は見た目の位置と違うので、画像クリックで色を取得するには一工夫
 
Dpi、ドットパーインチ、1インチに並んでいるピクセルの数
画像ファイルによってDpiの数値は様々
携帯やデジカメは72Dpiとか
Windowsの標準は96Dpiで表示
スキャナで取り込んだものは600Dpiとかいろいろある
WPFで作ったアプリで普通に表示するとDpiが反映されたサイズで表示される
 
DpiがいくつなのかJpeg画像ならファイルのプロパティで確認できる
イメージ 2
 
WPFのBitmapImageに画像ファイルを渡してImageのSourceに指定すると
Dpiが考慮された表示になる
100x100ピクセルの画像をWindows標準の96Dpiで表示する時
96Dpiの画像なら96/96*100=100x100ピクセルの大きさで表示される
72Dpiの画像は96/72*100=133.33333x133.33333…
600Dpiは96/600*100=16x16
 
 
イメージ 1
どちらも同じ256x192ピクセルの画像
これを表示しているWindowsは標準の96Dpiに設定してあるので
Dpiが96の画像だと1ドットに1ピクセルが表示されるので256x192ピクセル
そのまま表示される
Dpiが72だと少し引き伸ばされたように表示される
 
Dpi72、256x192ピクセルの画像を表示した時の
ImageとそのSource(画像)
イメージ 3
引き伸ばされて341.3x256で表示されている
画像をクリックするときは表示されているものをクリックするわけだから
341x256の中のどこか1点ってことになる
でも中の画像は256x192なので変換が必要になる
 
クリックした場所が(x,y)のとき中の画像の位置(nx,ny)は
nx = 画像のDpi/96*x
ny = 画像のDpi/96*y
 
クリックした場所が100,156なら
72/96*100=75
72/96*156=117
中の画像の75,117になる


別の方法
画像を読み込むときにDpiを96に変更して表示する
これなら見た目通りの位置とサイズになるので変換の必要がなくなる
でもこのDpiを変更ってのが簡単じゃない

BitmapとDpiの数値を渡すとDpi変更したBitmapを返す
'BitmapSourceのDpi変更、対応ピクセルフォーマットはBgra32だけ
Private Function ChangeDpi(b As BitmapSource, Optional x As Double = 96,
                               Optional y As Double = 96) As CachedBitmap
Dim stride As Integer = b.PixelWidth * 4
Dim pixels(b.PixelHeight * stride - 1) As Byte
b.CopyPixels(pixels, stride, 0)
        'BitmapSource.Createから作成したBitmapはCachedBitmapになるみたい
Dim cb As CachedBitmap = BitmapSource.Create(
b.PixelWidth, b.PixelHeight, x, y, PixelFormats.Bgra32, Nothing, pixels, stride)
        Return cb
    End Function
これで変更できるけどもっといい方法があるはず
渡されたBitmapをCopyPixelsメソッドでByte配列にバラバラにして
それを元に新たにBitmapSourceを作って返しているだけ
BitmapSourceのCreateでDpiを指定できるのでそれを利用している
 
ChangeDpiはBgra32しか対応していないので
読み込んだ画像をBgra32に変換しておく必要がある
これはFormatConvertedBitmapっていう便利なのがあるので
FormatConvertedBitmap(BitmapSource, PixelFormats.Bgra32, Nothing, 0)
これで変換できる
 
イメージ 4
上が座標変換で
下がDpi変換
 
次回は指定した色を透明にするになる予定
 
WPFVB.NETで画像の中の特定の色を透明にする ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/13957183.html
 
 
 
関連記事
WPF、dpiの変更とUseLayoutRoundingを指定して画像をくっきり表示 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15316739.html