none
カラーのビットパターンで描画したい。

    質問

  • ①まずカラーのビットパターン(5×5)を作成して

    ②そのビットパターンで(10×10)の画像(50×50=2500dot)をForm上に表示したいのですが

    どうすればよいでしょうか?

     

    描画の基本から分かっていないので、すみませんがよろしくお願いいたします。

    2008年8月6日 12:01

回答

  • さて、最後に「画像を交互に並べる」という部分です。
    交互にならべるためには、まず画像を2つ読み込まなければなりません。画像の読み込みの部分を2つに増やします。
     
    次に必要なことは、「どちらの画像を描画するべきか?」ということを判断しなければならない点です。このあたりのアルゴリズムの考え方は、やはり書籍などで勉強するのが手早いと思いますが、ここまでの処理を残してシンプルに作ると
     
    Code Snippet

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
      using (Image image1 = Image.FromFile("testC1.bmp"))
      using (Image image2 = Image.FromFile("testC2.bmp"))
      {
        bool isOddLine = true;
     
        for (int x = 0; x < 10; x ++)
        {
          // 偶数列は image1 を最初に描画する (= true)
          // 奇数列は image2 を最初に描画する (= false)
          bool drawImage1 = isOddLine;
     
          // 交互になるように、isOddLine を反転する
          isOddLine = !isOddLine;
     
          for (int y = 0; y < 10; y ++)
          {
            Point upperLeftCorner = new Point(x * 5, y * 5);
     
            // 画像を描画する
            if (drawImage1)
              e.Graphics.DrawImage(image1, upperLeftCorner);
            else
              e.Graphics.DrawImage(image2, upperLeftCorner);
     
            // 交互になるように drawImage1 を反転する
            drawImage1 = !drawImage1;
          }
        }
      }
    }

     

     

    こんなイメージになりますでしょうか? 一気に処理がふえていますが、何をやっているのか理解できますか? x と y の数字をつかって数式でシンプルに計算する方法もありますが、とりあえず条件分岐で処理をするかたちにしてみました。
     
    とりあえず、この時点で当初の目的は達成できているのですが、フォームの Paint イベントは描画が必要になるたびに呼び出されるようになっています。つまり、このままではフォームを描画するたびに画像をファイルから読み込みにいくため、すこしよろしくないかんじになります。
     
    画像の読み込みは、アプリケーションを起動したら1度だけでよいはずですね? フォームのイベントの一覧をながめたり、調べたり、していけば、Load イベントで画像を準備しておけることに気がつけるかもしれません。
     
    Code Snippet

    private Image image1;
    private Image image2;
     
    private void Form_Load(object sender, EventArgs e)
    {
      image1 = Image.FromFile("testC1.bmp"))
      image2 = Image.FromFile("testC2.bmp"))
    }
     
    private void Form_Closed(object sender, EventArgs e)
    {
      image1.Dispose();
      image2.Dispose();
    }
     
    private void Form1_Paint(object sender, PaintEventArgs e)
    {
      bool isOddLine = true;
     
      for (int x = 0; x < 10; x ++)
      {
        // 偶数列は image1 を最初に描画する (= true)
        // 奇数列は image2 を最初に描画する (= false)
        bool drawImage1 = isOddLine;
     
        // 交互になるように、isOddLine を反転する
        isOddLine = !isOddLine;
     
        for (int y = 0; y < 10; y ++)
        {
          Point upperLeftCorner = new Point(x * 5, y * 5);
     
          // 画像を描画する
          if (drawImage1)
            e.Graphics.DrawImage(image1, upperLeftCorner);
          else
            e.Graphics.DrawImage(image2, upperLeftCorner);
     
          // 交互になるように drawImage1 を反転する
          drawImage1 = !drawImage1;
        }
      }
    }

     

     

    using がなくなったかわりに Dispose が入っていたりしますが、やっていることは基本的に同じです。
     
    なお、すべてのサンプルコードは、私は実際に試していない手書きのコードです。内容の解説をしているので、コンパイルエラーになったり動作しなかったりした場合は、なにをやろうとしているのかを読み取って修正してみてください。
    2008年8月11日 18:46

すべての返信

  • この内容では、acslearner さんが、何が可能で何が不可能なのか、何が理解できて何に困っているのかがまったく読み取れません。
    具体的に問題となっている点や、考えていることをきちんと記述すると適切なレスポンスが得られるのではないでしょうか?
     
     
    とりあえず、どこで詰まっているのかわからないので、1点だけ
     
    カラーのビットパターンを保持するのは、後のことを考えると画像として保持するのが楽だと思います。この場合も手法は2つあって、
     
    ・ビットパターンを白黒の画像で保持して、カラー情報を別に持つ
    ・カラーの画像に色ごと保存する
     
    という方法です。5×5程度の小さい画像であれば、カラーで保持してもたいした情報量にならないので必要な色深度をもったカラー画像として保持すると良いかと思います。
     
    2008年8月7日 10:20
  • 5×5pixel深さ24bitの画像を2種類(testC1.bmp,testC2.bmp)準備しました。

    Form上に、2種類の画像を交互にタイル状に横に10個すきまなく並べることを、まず考えたいのですが、

    コードが全く浮かびません。

     

    2008年8月8日 6:07
  • 3度ぐらいにわけて応対するのがよさそうなのですが、一気に書いちゃいますね。
     
    まず、最初にやるべきことを日本語で考えてみてください。
    • 画像ファイル testC1.bmp を読み込み
    • 読み込んだ画像をフォームに表示する
    というのが基本的な処理になることはわかりますね?
    画像をファイルから読み込む場合は、System.Drawing.Image クラスあたりを利用すると良いでしょう。
     
    このクラス名を発見することが難しいかもしれませんが、ヘルプを「画像」などで検索すると見つかるかな?と思います。また、このクラスを発見することができれば、このクラスのヘルプからいくつかのサンプルコードや、System.Drawing.Bitmap クラスイメージ、ビットマップ、およびメタファイルイメージ、ビットマップ、アイコン、およびメタファイルの操作といったHOWTO文章も発見できるでしょう。(これらのリンクはオンラインヘルプにつながっていますが、インストールされているヘルプでも同様です)
     
    このあたりについては、体系的に学習できる書籍や web サイトをざっくりと読まれるほうが理解は早いと思います。
     
    これらのヘルプをうまいこと読み取っていけば
    • 画像ファイル testC1.bmp を読み込み
      → Image クラスの FromFile メソッドでよさそうだ
    というところまでわかれば、実装もある程度みえてくると思います。ヘルプのサンプルなどを見て、
     
    Code Snippet
     
    using (Image image1 = Image.FromFile("testC1.bmp"))
    {
      // ここで image1 をフォームに表示する
    }

     

     

    という実装になります。
    2008年8月11日 17:58
  • 次に、
    • 読み込んだ画像をフォームに表示する
    という部分ですが、これはよく詰まる人がいる部分です。Windows の描画システムに関する理解がある程度必要なので、やはり書籍や web サイト、ヘルプの Windows Form アプリケーションの開発関連についてをきちんと読んでほしいところです。
     
    Form に画像を表示するには、おもに3つの方法があります。
    • PictureBox コントロールなどをフォームに配置して表示する
    • Form の BackgorundImage に画像を指定する
    • Form の Paint メソッドを使用して自分で描画する
    というものです。
     
    おそらく1つめは試されていると思うので飛ばします。
     
    次のBackgroundImage プロパティは、一見使えそうだと思われると思いますし、こちらも試されているかもしれませんが、「2つの画像を交互に並べる」という部分に少しひっかかるところがあるため、断念されたかもしれません。
     
    もし、↑のように、実際に BackgroundImage が使えるかどうかと考えたり、それを試していたりしていたのであれば、そういったことを最初に書いておくと、返答をする人たちの参考になってよいです。
     
    というわけで、最後の Paint イベントを利用することを考えましょう。ヘルプでは、文章と線を引くサンプルが記載されていますが、このサンプルをみて、描画処理は System.Drawing.Graphics クラスを使用するということに気がつかれるでしょうか? これが気がつけないようであれば、繰り返しになりますが、書籍や web サイトなどで体系的に学ばれることをおすすめします。
     
    さて、Graphics クラスについても調べてみると、ズバリ画像を描画するサンプルが記載されています。前の投稿で書いたように Image クラスを使用したものですので、これはすぐに利用できると思います。Visual Studio を使用して Form の Paint イベントをダブルクリックすると、
    Code Snippet
     
    private void Form1_Paint(object sender, PaintEventArgs e)
    {
      
    }

     

     

    のようなコードが自動的に作成されますので、Paint イベントのサンプルと Graphics クラスのサンプルを参考に、前の投稿に書いたコードとあわせると
     
    Code Snippet
     
    private void Form1_Paint(object sender, PaintEventArgs e)
    {
      using (Image image1 = Image.FromFile("testC1.bmp"))
      {
        // 左上は 0,0 です
        Point upperLeftCorner = new Point(0, 0);
     
        // 画像を描画する
        e.Graphics.DrawImage(image1, upperLeftCorner);
      }
    }

     

     

    このような感じになりますでしょうか? これを実行すると、フォームの左上に testC1.bmp が表示されると思います。
    あとは、
    • フォームに画像を10個表示する
    • 2つの画像を交互に表示する
    という2つの点をクリアしなければなりませんね。
    まず、前者ですが繰り返し構造をつかって画像を何度も描画すればよいことがわかりますでしょうか? 繰り返し構造は for 文を使用して、
     
    Code Snippet
     
    for (int x = 0; x < 10; x ++)
    {
      for (int y = 0; y < 10; y ++)
      {
        Point upperLeftCorner = new Point(x * 5, y * 5);
     
        e.Graphics.DrawImage(image1, upperLeftCorner);
      }
    }

     

     

    などとすると、testC1.bmp が上下左右に10個並ぶことがわかると思います。繰り返しになりますが、上のようなループによる描画が理解できないようであれば書籍や(略)

     

    さて、このコードでは画像のサイズが 5×5 であることを決め撃ちしているので、5 をかけないで image1.Width と image1.Height を利用すると画像の大きさが大きくなったり小さくなったりしても大丈夫になります。このあたりは要求に応じて考えてください。

     

    ここまでをまとめると、

    Code Snippet
     
    private void Form1_Paint(object sender, PaintEventArgs e)
    {
      using (Image image1 = Image.FromFile("testC1.bmp"))
      {
        for (int x = 0; x < 10; x ++)
        {
          for (int y = 0; y < 10; y++)
          {
            Point upperLeftCorner = new Point(x * 5, y * 5);
     
            // 画像を描画する
            e.Graphics.DrawImage(image1, upperLeftCorner);
          }
        }
      }
    }

     

     

    こんなかんじになりますね。
    2008年8月11日 18:31
  • さて、最後に「画像を交互に並べる」という部分です。
    交互にならべるためには、まず画像を2つ読み込まなければなりません。画像の読み込みの部分を2つに増やします。
     
    次に必要なことは、「どちらの画像を描画するべきか?」ということを判断しなければならない点です。このあたりのアルゴリズムの考え方は、やはり書籍などで勉強するのが手早いと思いますが、ここまでの処理を残してシンプルに作ると
     
    Code Snippet

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
      using (Image image1 = Image.FromFile("testC1.bmp"))
      using (Image image2 = Image.FromFile("testC2.bmp"))
      {
        bool isOddLine = true;
     
        for (int x = 0; x < 10; x ++)
        {
          // 偶数列は image1 を最初に描画する (= true)
          // 奇数列は image2 を最初に描画する (= false)
          bool drawImage1 = isOddLine;
     
          // 交互になるように、isOddLine を反転する
          isOddLine = !isOddLine;
     
          for (int y = 0; y < 10; y ++)
          {
            Point upperLeftCorner = new Point(x * 5, y * 5);
     
            // 画像を描画する
            if (drawImage1)
              e.Graphics.DrawImage(image1, upperLeftCorner);
            else
              e.Graphics.DrawImage(image2, upperLeftCorner);
     
            // 交互になるように drawImage1 を反転する
            drawImage1 = !drawImage1;
          }
        }
      }
    }

     

     

    こんなイメージになりますでしょうか? 一気に処理がふえていますが、何をやっているのか理解できますか? x と y の数字をつかって数式でシンプルに計算する方法もありますが、とりあえず条件分岐で処理をするかたちにしてみました。
     
    とりあえず、この時点で当初の目的は達成できているのですが、フォームの Paint イベントは描画が必要になるたびに呼び出されるようになっています。つまり、このままではフォームを描画するたびに画像をファイルから読み込みにいくため、すこしよろしくないかんじになります。
     
    画像の読み込みは、アプリケーションを起動したら1度だけでよいはずですね? フォームのイベントの一覧をながめたり、調べたり、していけば、Load イベントで画像を準備しておけることに気がつけるかもしれません。
     
    Code Snippet

    private Image image1;
    private Image image2;
     
    private void Form_Load(object sender, EventArgs e)
    {
      image1 = Image.FromFile("testC1.bmp"))
      image2 = Image.FromFile("testC2.bmp"))
    }
     
    private void Form_Closed(object sender, EventArgs e)
    {
      image1.Dispose();
      image2.Dispose();
    }
     
    private void Form1_Paint(object sender, PaintEventArgs e)
    {
      bool isOddLine = true;
     
      for (int x = 0; x < 10; x ++)
      {
        // 偶数列は image1 を最初に描画する (= true)
        // 奇数列は image2 を最初に描画する (= false)
        bool drawImage1 = isOddLine;
     
        // 交互になるように、isOddLine を反転する
        isOddLine = !isOddLine;
     
        for (int y = 0; y < 10; y ++)
        {
          Point upperLeftCorner = new Point(x * 5, y * 5);
     
          // 画像を描画する
          if (drawImage1)
            e.Graphics.DrawImage(image1, upperLeftCorner);
          else
            e.Graphics.DrawImage(image2, upperLeftCorner);
     
          // 交互になるように drawImage1 を反転する
          drawImage1 = !drawImage1;
        }
      }
    }

     

     

    using がなくなったかわりに Dispose が入っていたりしますが、やっていることは基本的に同じです。
     
    なお、すべてのサンプルコードは、私は実際に試していない手書きのコードです。内容の解説をしているので、コンパイルエラーになったり動作しなかったりした場合は、なにをやろうとしているのかを読み取って修正してみてください。
    2008年8月11日 18:46
  • 懇切に教えてくださり本当にありがとうございました。本なども参考にして成功しました。

    Form_Paintのなかで

    Code Snippet

    Bitmap baseBmp1=null;

    baseBmp=new Bitmap("testC1.bmp");

    e.Graphics.DrawImage(baseBmp,0,0);

     

     

    Form_Loadのなかで

    ivalidate();

     

    というものでした。

    2008年8月12日 3:57