- PR -

byte配列からのBitmap作成

1
投稿者投稿内容
UK
常連さん
会議室デビュー日: 2005/04/11
投稿数: 32
投稿日時: 2006-08-24 17:07
こんにちは。

画像に手を加えるために、(SetPixelは非常に処理が遅いので)、byte配列を使用して処理を行っています。

処理が終わった画像を表示しているのですが、表示されているフォームをグリグリ動かし回ったりすると、AccessViolationExceptionが投げられます。

byte配列からビットマップを作成するために、Bitmap(Int32, Int32, Int32, PixelFormat, IntPtr)のコンストラクタを使用しています。
IntPtrを取得するためにGCHandle.Alloc(obj, GCHandleType.Pinned)を使用しています。

やはりGCHandleを利用するのが怪しいのでしょうか。
このあたりの挙動がわからず困っています。
他にbyte配列からBitmapを作成する方法があればご教授いただきたいです。

なお、環境はXP Pro SP2 + VS2005(C#)です。
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-08-24 17:45
まあ使わないに越したことは無いですね。その意味がわからないうちは特に。

Bitmap.LockBits
Marshal.Copy
処理
Marshal.Copy
Bitmap.UnlockBits

と言う手順を踏むのが基本です。
unsafe、あるいは Marshal クラスのメンバを使えば Scan0 からバイト配列にコピーせず直接メモリを操作できます。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2006-08-24 22:02
引用:

処理が終わった画像を表示しているのですが、表示されているフォームをグリグリ動かし回ったりすると、AccessViolationExceptionが投げられます。


 おそらく、Paint イベント発生毎に「byte配列からビットマップを作成するために・・・」をされているのだと思うのですが、最初の1回だけ作って、それをクラスメンバに退避しておき、次回以降の Paint イベントでは、退避しておいたビットマップを用いればいいのではないですか?
rvmx
大ベテラン
会議室デビュー日: 2002/09/26
投稿数: 184
お住まい・勤務地: 愛媛県
投稿日時: 2006-08-25 05:50
今日は

引用:
他にbyte配列からBitmapを作成する方法があれば



Byte配列をMemoryStreamへ書き込み、ImageFromStreamでBitMapが作れると思います。
UK
常連さん
会議室デビュー日: 2005/04/11
投稿数: 32
投稿日時: 2006-08-25 18:24
ご返答ありがとうございます。

>Hongliangさん
ライブラリの仕様上、Bitmapではなく初めからbyte配列となっているのでその方法は無理そうです・・・。

>Jittaさん
外部映像入力からbyte配列を生成しています。
byte配列から現在の方法でBitmapを作成するにはコンストラクタしかなく、中間処理をかます都合上、同じ配列とは限らないのでその方法も難しそうです。

>rvmxさん
この方法が現実的そうのなですが、いろいろ見てみてもやり方がわかりません。
どのようにやればいいのでしょうか。
かめたろ
ぬし
会議室デビュー日: 2003/03/20
投稿数: 255
投稿日時: 2006-08-25 18:45
引用:

>rvmxさん
この方法が現実的そうのなですが、いろいろ見てみてもやり方がわかりません。
どのようにやればいいのでしょうか。


いま、まさにFromStreamを使ってたところです。タイムリーだったのでびっくり。
コード:
    Dim Img() As Byte
    Img = byte配列
    Dim mems As New MemoryStream(Img)
    Dim newImage As Image = Image.FromStream(mems)


Bitmap を作るには newImage を Bitmap のコンストラクタの引数にぶち込めばいいのかな
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-08-25 19:18
Bitmap (Int32, Int32, Int32, PixelFormat, IntPtr) を使うってことはヘッダが存在していないデータだろうから Image.FromStream/Bitmap(Stream) じゃ無理じゃないかなぁ……。

Bitmap (Int32, Int32, PixelFormat) を使って空の Bitmap を作成しておき、それを LockBits して Scan0 にコピーすれば行けそう?
Kazuki
ぬし
会議室デビュー日: 2004/10/13
投稿数: 298
投稿日時: 2006-08-28 09:01
引用:

Hongliangさんの書き込み (2006-08-25 19:18) より:
Bitmap (Int32, Int32, Int32, PixelFormat, IntPtr) を使うってことはヘッダが存在していないデータだろうから Image.FromStream/Bitmap(Stream) じゃ無理じゃないかなぁ……。

Bitmap (Int32, Int32, PixelFormat) を使って空の Bitmap を作成しておき、それを LockBits して Scan0 にコピーすれば行けそう?



下のでとりあえず表示できたんでいけそうな気がしますね。
コード:
private void Form1_Paint(object sender, PaintEventArgs e)
{
    byte[] dat = new byte[100 * 100 * 3];
    for (int h = 0; h < 100; h++)
    {
        for (int w = 0; w < 100; w++)
        {
            // 真っ赤なデータを用意
            int index = h * 100 * 3 + w * 3;
            dat[index] = 0;
            dat[index + 1] = 0;
            dat[index + 2] = 255;
        }
    }

    using (Bitmap bmp = new Bitmap(100, 100, PixelFormat.Format24bppRgb))
    {
        BitmapData bd = bmp.LockBits(
            new Rectangle(0, 0, 100, 100),
            ImageLockMode.WriteOnly,
            PixelFormat.Format24bppRgb);

        Marshal.Copy(dat, 0, bd.Scan0, dat.Length);

        bmp.UnlockBits(bd);

        e.Graphics.DrawImage(bmp, 0, 0);
    }
}

1

スキルアップ/キャリアアップ(JOB@IT)