C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Bitmapを自動拡大縮小して、PictureBoxに表示

[トピック内 22 記事 (1 - 20 表示)]  << 0 | 1 >>

■88277 / inTopicNo.1)  Bitmapを自動拡大縮小して、PictureBoxに表示
  
□投稿者/ バカボンド (1回)-(2018/08/17(Fri) 23:00:18)

分類:[.NET 全般] 

VB.NETを使っております。

256x256のバイト配列データがあり、
これを自動拡大縮小してPictureBoxに表示したいと考えています。



Dim img As Bitmap = New Bitmap(256, 256, PixelFormat.Format8bppIndexed)

img.Palette = カラーインデックス生成

Dim data As BitmapData = img.LockBits(New Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed)


For y = 0 To 256 - 1
For x = 0 To 256 - 1

Marshal.WriteByte(data.Scan0, y * data.Stride + x, Byte_Hairetu(x + 1, y + 1))

Next x
Next y


img.UnlockBits(data)

のようにして、バイト配列をbitmapデータに変換することができます。

あとはこれをPictureBoxに表示するだけなのですが、
なぜかこれがうまくいきません。

スケーリングして表示する方法は
https://dobon.net/vb/dotnet/graphics/drawimage.html#scaling

このページに書かれてあり、
ファイルからPictureBoxにスケーリングして表示する方法は分かりました。

上記のコードで得られたBitmapデータをimageデータに変換して、
PictureBoxに表示したいのですが
どのようなコードを書けば良いでしょうか?




引用返信 編集キー/
■88278 / inTopicNo.2)  Re[1]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ Azulean (970回)-(2018/08/18(Sat) 00:13:02)
あまりこだわりがなければ、その作成した img を PictureBox の Image プロパティに設定し、SizeMode プロパティで Zoom にすれば PictureBox に合わせて拡大縮小してくれると思います。

https://msdn.microsoft.com/ja-jp/library/system.windows.forms.pictureboxsizemode%28v=vs.110%29.aspx
https://msdn.microsoft.com/ja-jp/library/system.windows.forms.picturebox.sizemode%28v=vs.110%29.aspx

-----
そのスケーリングのサンプルコードに沿いたい場合は、Image.FromFile を使わず、あなたが書いたコードの img を第1引数に指定して DrawImage すれば良いだけです。
サイズの計算(縦横比の維持)などは自分で考える必要があります。
手間であれば、上に書いた SizeMode プロパティでお手軽に済ませられるとは思います。
引用返信 編集キー/
■88279 / inTopicNo.3)  Re[2]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ バカボンド (2回)-(2018/08/18(Sat) 09:36:21)
ありがとうございます。

試してみたのですが


PictureBox1.Image = img
のところで、使用されたパラメータが有効ではありません
というエラーが出てうまくいきません
どうすれば良いですか?

https://dobon.net/vb/dotnet/graphics/createimage.html

Dim img As New Bitmap(200, 100)

'ImageオブジェクトのGraphicsオブジェクトを作成する
Dim g As Graphics = Graphics.FromImage(img)

'全体を黒で塗りつぶす
g.FillRectangle(Brushes.Black, g.VisibleClipBounds)
'黄色い扇形を描画する
g.DrawPie(Pens.Yellow, 60, 10, 80, 80, 30, 300)

'リソースを解放する
g.Dispose()

'作成した画像を表示する
PictureBox1.Image = img


だと、うまく表示できるのですが
何が違うのでしょうか・・・?

引用返信 編集キー/
■88280 / inTopicNo.4)  Re[3]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ バカボンド (4回)-(2018/08/18(Sat) 10:32:17)
エラーの原因が分かりました。
Dim img As Bitmap = New Bitmap(256, 256, PixelFormat.Format8bppIndexed)



img.UnlockBits(data)

のコードをバックグラウンドで行っていたたため、

frm.BeginInvoke()


img.Dispose()

のようして、デレゲートで画像表示を行っているのが原因でした。
Disposeの前に
Thread.Sleep(100)

を入れてやり、画像が表示される前にdisposeされないようにすると
うまく表示できました。

しかし、これってどうすれば良いですか?
同期処理であるInvokeも試してみたのですが
やはりエラーになってしまいます。

画像が表示されるのを待ってから
imgをdisposeしたいのですが
どのようにすれば良いですか?

引用返信 編集キー/
■88282 / inTopicNo.5)  Re[4]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ Azulean (971回)-(2018/08/18(Sat) 16:14:27)
No88280 (バカボンド さん) に返信
> 画像が表示されるのを待ってから
> imgをdisposeしたいのですが
> どのようにすれば良いですか?

PictureBox の Image プロパティに設定する画像は Dispose してはいけません。
(もし、次に Image プロパティに新たな画像を設定することがあるなら、そのときに前の画像を Dispose する)
引用返信 編集キー/
■88285 / inTopicNo.6)  Re[5]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ バカボンド (6回)-(2018/08/18(Sat) 17:40:14)
後から新たな画像を設定する場合でも
画像をdisposeしなくとも、特にエラーもなく問題ないのですが
新たな画像に設定する場合にはdisposeする必要がありますか?
もししなかったら何か不都合がありますか?

自分が主に、画像をpublic変数にしてしまって、
フォームを閉じる時にdisposeすれば良いのではないかと思ったのですが
これでも問題ないのでしょうか?

引用返信 編集キー/
■88286 / inTopicNo.7)  Re[6]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ Azulean (973回)-(2018/08/18(Sat) 17:52:42)
No88285 (バカボンド さん) に返信
> 新たな画像に設定する場合にはdisposeする必要がありますか?
> もししなかったら何か不都合がありますか?

基本的に IDisposable を実現するクラスのオブジェクトは不要になった時点で Dispose した方が良いとは思います。
後で Dispose するでも構いませんが、対象のオブジェクト次第ではリソースを消費したまま(ロックしたまま)となることがありますので、時と場合によります。

> 自分が主に、画像をpublic変数にしてしまって、
> フォームを閉じる時にdisposeすれば良いのではないかと思ったのですが
> これでも問題ないのでしょうか?

昨今の Bitmap であれば、小さなサイズであれば後で Dispose でも間に合うと思います。
(巨大な Bitmap であればその生存期間は短くした方が良いといえますが)
引用返信 編集キー/
■88288 / inTopicNo.8)  Re[7]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ バカボンド (7回)-(2018/08/18(Sat) 18:35:39)
> 昨今の Bitmap であれば、小さなサイズであれば後で Dispose でも間に合うと思います。
> (巨大な Bitmap であればその生存期間は短くした方が良いといえますが)

public変数にしてしまって、
画像を新しくする時も同じimgをdiposeせずに
使い回せば、メモリの使用量は増えないと思うのですが
合っていますでしょうか?



引用返信 編集キー/
■88289 / inTopicNo.9)  Re[8]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ Hongliang (676回)-(2018/08/18(Sat) 18:42:51)
2018/08/18(Sat) 18:45:05 編集(投稿者)

変数とインスタンスは関係ありません。
Dim a As Bitmap = New Bitmap(...)
a = New Bitmap(...)
とした場合、1回目にNewされたBitmapと2回目にNewされたBitmapは別々のメモリ領域に確保されます。
1回目にNewされたBitmapは、このコードの場合だともうアクセスできなくなるので、ガベージコレクタによって片付けられるまでメモリを占有し続けます。

Dim old As Bitmap = a
a = New Bitmap(...)
If Not(old Is Nothing) Then
old.Dispose()
End If
のようにするなどして古いのを片付けるようにします。
引用返信 編集キー/
■88290 / inTopicNo.10)  Re[9]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ バカボンド (8回)-(2018/08/18(Sat) 18:51:40)

ありがとうございます。

そうだったのですが、勉強になりました。

ちなみに、一度aをoldにコピーしてから
コピー先のoldをdisposeするというのが、何となく二度手間のような気がします。



Dim a As Bitmap = New Bitmap(...)
If aがdisposeされたか調べる Then
a.Dispose()
End If


a = New Bitmap(...)

のようにした方が分かりやすいのではないかと思うのですが
imageがdisposeされたかどうか調べるコマンドはないのでしょうか?


引用返信 編集キー/
■88291 / inTopicNo.11)  Re[10]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ Azulean (975回)-(2018/08/18(Sat) 18:56:47)
No88290 (バカボンド さん) に返信
> ちなみに、一度aをoldにコピーしてから
> コピー先のoldをdisposeするというのが、何となく二度手間のような気がします。

であれば、a を Dispose して、直後に New したものを a に入れればよいです。
リスクはありますが、メインスレッドで処理しているならほぼ大丈夫でしょう。


> Dim a As Bitmap = New Bitmap(...)
> If aがdisposeされたか調べる Then
> a.Dispose()
> End If

考え違いしていそうです。

・Dispose されているのなら、Dispose する必要はありません。
 「不要になったのであれば Dispose する」という考え方を持ってください。

・a を New した直後であれば、それは必要なはずですから、直下に、条件つきとはいえ、Dispose する処理を書くのはおかしいです。
引用返信 編集キー/
■88292 / inTopicNo.12)  Re[11]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ バカボンド (9回)-(2018/08/18(Sat) 19:05:39)

そうですね
わかりにくかったです

Public a As Bitmap = New Bitmap(...)

Sub Gazo1

If aがdisposeされている = False Then
a.Dispose()
End If


a = New Bitmap(...)

End Sub


Sub Gazo2

For i = 1 to 1000

Call Gazo1

Next i

End Sub

というコードを書きたいのですが


引用返信 編集キー/
■88293 / inTopicNo.13)  Re[12]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ Azulean (976回)-(2018/08/18(Sat) 19:13:56)
No88292 (バカボンド さん) に返信
> If aがdisposeされている = False Then
> a.Dispose()
> End If

そもそも、「Dispose されているかどうか」を知りたいのではなく、「a に何か入っているか?」で済む話では?
すぐに後から a = New Bitmap とするわけですから。

そうであれば、a IsNot Nothing で済む話ではないでしょうか。

参考
https://smdn.jp/programming/vb.net/operator_is_isnot_typeof/

引用返信 編集キー/
■88294 / inTopicNo.14)  Re[13]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ バカボンド (11回)-(2018/08/18(Sat) 19:21:34)

いま気付いたのですが、



Dim img As Bitmap = New Bitmap(256, 256, PixelFormat.Format8bppIndexed)
img = New Bitmap(256, 256, PixelFormat.Format8bppIndexed)
・・・

を繰り返すと
メモリの使用量が増えていくと思います。
しかし、


Dim img As Bitmap = New Bitmap(256, 256, PixelFormat.Format8bppIndexed)

img.Palette = カラーインデックス生成

For z = 0 to 1000

Dim data As BitmapData = img.LockBits(New Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed)


For y = 0 To 256 - 1
For x = 0 To 256 - 1

Marshal.WriteByte(data.Scan0, y * data.Stride + x, Byte_Hairetu(x + 1, y + 1, z))

Next x
Next y

img.UnlockBits(data)

Next z

とするなら、メモリ使用量は変わらないのではないでしょうか?



引用返信 編集キー/
■88295 / inTopicNo.15)  Re[14]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ Azulean (977回)-(2018/08/18(Sat) 19:28:46)
No88294 (バカボンド さん) に返信
> とするなら、メモリ使用量は変わらないのではないでしょうか?

同じインスタンスの中身を書き換える場合はそうですね。
ただ、PictureBox は img の中身が変わったことを自力で検知できないので、書き換えた後、PictureBox に対して Invalidate を呼んであげないと結果が画面に反映されません。

また、PictureBox が画像を画面に描画する処理のタイミングと、LockBits/UnlockBits のタイミングが重なると、どちらかで例外が発生すると思われます。
どちらもメインスレッドで処理するなら問題ありませんが。

引用返信 編集キー/
■88296 / inTopicNo.16)  Re[15]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ バカボンド (12回)-(2018/08/18(Sat) 19:37:09)
> また、PictureBox が画像を画面に描画する処理のタイミングと、LockBits/UnlockBits のタイミングが重なると、どちらかで例外が発生すると思われます。
> どちらもメインスレッドで処理するなら問題ありませんが。


これは、そうなのですか・・・?
どうしてもマルチスレッド処理する必要があるのですが
どのようにして排他処理すれば良いのでしょうか?



引用返信 編集キー/
■88297 / inTopicNo.17)  Re[16]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ Azulean (978回)-(2018/08/18(Sat) 19:48:56)
No88296 (バカボンド さん) に返信
> どうしてもマルチスレッド処理する必要があるのですが
> どのようにして排他処理すれば良いのでしょうか?

マルチスレッドで処理するなら、インスタンスは分けた方が良いでしょうね。

バックグラウンド側
 1.Bitmap を作成
 2.Bitmap を LockBits して書き込み
 3.Bitmap を UnlockBits
 4.BeginInvoke などで作成した Bitmap をメインスレッドに渡す

メインスレッド側
 1.PictureBox の Image プロパティに設定されている Bitmap があれば Dispose
 2.渡された Bitmap をPictureBox の Image プロパティに設定
 3.PictureBox の Invalidate を呼び出して再描画
引用返信 編集キー/
■88298 / inTopicNo.18)  Re[17]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ バカボンド (13回)-(2018/08/18(Sat) 19:55:01)
ありがとうございます。

PictureBox の Image プロパティに設定されている Bitmap があれば Dispose

これって単に

If PictureBox1.Image isnot Nothing then

で調べられますか?

引用返信 編集キー/
■88299 / inTopicNo.19)  Re[18]: Bitmapを自動拡大縮小して、PictureBoxに表示
□投稿者/ Azulean (979回)-(2018/08/18(Sat) 19:56:34)
No88298 (バカボンド さん) に返信
> これって単に
>
> If PictureBox1.Image isnot Nothing then
>
> で調べられますか?

はい。
というか、試しましょう。

余談
参照型についての理解が不十分ゆえに、不安に感じるのかもしれません。
「値型と参照型の違い」「GC(ガベージコレクション)」「IDisposable」あたりを学んでいただけると知識と自信をつけていけるかと思えます。
引用返信 編集キー/
■88300 / inTopicNo.20)  Re[19]: Bitmapを自動拡大縮小して、PictureBoxに表示
 
□投稿者/ バカボンド (15回)-(2018/08/18(Sat) 20:05:24)
ありがとうございます。

「値型と参照型の違い」について理解しているつもりなのですが、
値型で渡したはずなのに
BeginInvoleだとなぜか参照型になってしまうのですが・・・
これは仕方のないことですか?

引用返信 編集キー/

このトピックをツリーで一括表示

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -