午後わてんのブログ

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

WPF、アプリのウィンドウに画像ファイルドロップで画像表示テスト

WPFVB
エクスプローラなどから画像ファイルドロップしてウィンドウに画像を表示
 
参照したところは
方法: RichTextBox コントロール上にドロップしたファイルを開く
    https://msdn.microsoft.com/ja-jp/library/hh144798(v=vs.110).aspx
よしいずの雑記帳WPF のサンプルコード 画像ファイルの読込と保存
http://yoshiiz.blog129.fc2.com/blog-entry-818.html
片鱗懐古のブログ:   wpf : 画像ファイルをロックせずにBitmapSourceを読み込む
http://pieceofnostalgy.blogspot.jp/2012/02/wpf-bitmapsource.html
この辺り
WPF関連でググッて見つかるところは圧倒的にC#が多くてVBはかなり少ない
上記の参照したところも下2つはC#
もっとVB増えてほしいなあ

今回テストで作ってみたのがこれ
イメージ 2
アプリのウィンドウに画像ファイルをドロップすると
イメージ 3
その画像を表示
デザイン画面

f:id:gogowaten:20191024155005p:plain

WindowのAllowDropにチェックを入れてファイルのドロップを受付可能にする
Gridに名前をつける、grid1って名前にした
 
VBのコード

f:id:gogowaten:20191024155017p:plain

Imports System.IO

Class MainWindow
    Private Sub MainWindow_Drop(sender As Object, e As DragEventArgs) Handles Me.Drop
        'ドロップされたファイルのパスを取得
        Dim filesPath() As String = e.Data.GetData(DataFormats.FileDrop)
        'ファイルパスの画像を割り当てたImageコントロールをGridに表示
        Call AddImage(filesPath(0))
    End Sub

    'ファイルパスからBitmapImage(画像)を作成して返す
    Private Function GetBitmapImage(filePath As String) As BitmapImage
        Dim bmp As New BitmapImage
        Using fs As New FileStream(filePath, FileMode.Open, FileAccess.Read)
            With bmp
                .BeginInit()
                .StreamSource = fs
                .CacheOption = BitmapCacheOption.OnLoad
                .EndInit()
            End With
        End Using
        Return bmp
    End Function

    'ImageControlを作成してGridに追加
    Private Sub AddImage(filesPath As String)
        'ファイルパスからBitmapImage(画像)を取得
        Dim bmp As BitmapImage = GetBitmapImage(filesPath)
        'ImageControlを作成して画像やサイズを指定
        Dim img As New Image
        With img
            .Source = bmp
            .Width = bmp.PixelWidth
            .Height = bmp.PixelHeight
        End With
        'GridにImageを追加(表示)する
        grid1.Children.Add(img)
    End Sub
End Class
 
 
エラーの処理していないからウィンドウにドロップされたものが
画像ファイル以外だとエラーになるし
読み込めない種類の画像だったり
解像度がフルHDの100倍くらいの画像でもエラーになる
 
ドロップされた画像ファイルのパスを取得
画像ファイルからBitmapImage画像を作成
Imageコントロールを作成してSourceにBitmapImage画像を指定する
Imageコントロールをgrid1に追加して表示する
 
イメージ 5
4から9行目がWindowに何かがドロップされた時に動くDropイベント
6行目でドロップされたすべてのファイルパスを取得していて
ここはWindowsフォームアプリの時と同じだなあ
イメージ 6
複数のファイルをドロップした時に取得したファイルパス
複数ファイルの時でも今回は一つの画像だけ表示するので0番めのだけ表示する
 
ファイルパスからBitmapImage作成する
GetBitmapImage
イメージ 7
FileStreamに画像ファイルを読み込んで
今回の中で一番わからないこのBitmapImageに読み込んでいる
FileStreamを使うのは画像ファイルをロックさせないため
ロックされると画像を開いている間は元の画像ファイルの削除や
名前変更、移動などができなくなるから
 
BeginInitとEndInitは最初と最後に必要な物らしい、そういうものなんだなあって納得できる
StreamSourceにFileStreamを指定するのはわかる
わからないのがCacheOption、指定できるのはOnLoadのほかに
Default、None、OnDemandの4つあるけどOnLoad以外だと画像が表示されなかった
 
ファイルパスから作成した画像を表示するImageControlを作成して
grid1に追加して表示する
AddImage
イメージ 8
さっきのGetBitmapImageにファイルパスを渡してBitmapImageを取得
Imageコントロールを作成してSourceにBitmapImageを指定
Imageをgrid1に追加
 
33,34行目はImageコントロールの幅と高さを指定
この時はBitmapImage(画像)の幅と高さをもとにするんだけど
幅ならWidthじゃなくてPixelWidthの方がいいみたいで

f:id:gogowaten:20191024155037p:plain

イメージ 10
一時停止してBitmapImageの中を見てみる
PixelWidthは560だけど
Widthは560.07816133906931とか変な数値になっている
 
そんなこんなでできあがったImageコントロールをgridに追加するには
grid1.Children.Add(img)
ってChildrenってのを使うみたい
Windowsフォームアプリのときは
Form1.Controls.Add(img)
だったかな、微妙に違うw
 
ここまでで画像を表示する最低限のものはできた
画像ファイルから画像を取得する…と言うか画像データを作成するには
他にも方法があるみたいで
BitmapSourceを使う方法、さっきのはBitmapImageで名前似ている
イメージ 11
    'ファイルパスからBitmapSource(画像)を作成して返す
    Private Function GetBitmapSource(filePath As String) As BitmapSource
        Dim bmp As BitmapSource
        Using fs As New FileStream(filePath, FileMode.Open, FileAccess.Read)
            Dim bd As BitmapDecoder = BitmapDecoder.Create(
                fs, BitmapCreateOptions.None, BitmapCacheOption.Default)
            bmp = New WriteableBitmap(bd.Frames(0))
            bmp.Freeze()
        End Using
        Return bmp
    End Function

これを付け足して
 
イメージ 12
28行目をコメントアウトして
29行目を付け足し
これでも画像が表示される
 
46行目にあるBitmapCacheOption.DefaultはBitmapCacheOption.OnLoadでも
どちらでも画像が表示される
BitmapImageの時はOnLoad以外は表示されなかったんだけど
BitmapSourceだとDefaultでも問題ない、やっぱよくわからん
 
 
それぞれのプロパティ
BitmapImage

f:id:gogowaten:20191024155055p:plain

BitmapSource(WriteableBitmap)

f:id:gogowaten:20191024155105p:plain

青色の1行目のところを見ると
BitmapSourceだと思っていたけどWriteableBitmapっていうのが正しいのかな
2つを比べてわかったのが2つは微妙に違うってことだけで
どっちを使ったらいいのかはさっぱりわからん
 
 
今回の全文

f:id:gogowaten:20191024155116p:plain

 
BitmapSource クラス (System.Windows.Media.Imaging)
https://msdn.microsoft.com/ja-jp/library/system.windows.media.imaging.bitmapsource(v=vs.110).aspx
ここみたらBitmapSourceを継承したものがいろいろあって
その中にBitmapImageやWriteableBitmapってことみたい?
 
 
この記事の続きは
WPFVBでアプリ作る準備その1、マウスドラッグでコントロールの移動 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/13900213.html