DOBON.NET DOBON.NETプログラミング掲示板過去ログ

オフスクリーンの内容を同じオフスクリーンにコピーする

分類:[.NET]

オフスクリーンに同じオフスクリーンの内容をコピーしたいのですが
できますでしょうか?
やってみたのですができなかったのでもしできるなら教えてください
C#です。
> やってみたのですができなかったのでもしできるなら教えてください
> C#です。

できましたら(あまり長くないなら),やってみたコードを見せてください。
ではコード表示しますね
簡単に言うとオフスクリーンの一番右上端から32*32の大きさで描画処理して
その書いたオフスクリーンの画像を元にまた同じオフスクリーンに
描画したいのです。

amespace WindowsApplication1
{
public partial class Form1 : Form
{
private Image bufferImage;
private Graphics buf;


public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
}


//フォームを読み込む前の処理
private void Form1_Load(object sender, EventArgs e)
{

//オフスクリーンを作成する
bufferImage = new Bitmap(1400, 1000);
//オフスクリーンに描画できるようにする
buf = Graphics.FromImage(bufferImage);

BackGraund();

}

//オフスクリーンに背景の描画処理を1回だけする
private void BackGraund()
{

//ペンの作成
Brush brush1 = new SolidBrush(Color.Blue);
Brush brush2 = new SolidBrush(Color.White);

int a = 0;
int b = 0;

for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
if (b % 2 == 0)
{
//偶数なら緑ブラシ
if (a % 2 == 0)
{
buf.FillRectangle(brush1, x * 4, y * 4, 4, 4);
}
//奇数なら白ブラシ
else
{
buf.FillRectangle(brush2, x * 4, y * 4, 4, 4);
}
}
else
{
//偶数なら白ブラシ
if (a % 2 == 0)
{
buf.FillRectangle(brush2, x * 4, y * 4, 4, 4);
}
//奇数なら緑ブラシ
else
{
buf.FillRectangle(brush1, x * 4, y * 4, 4, 4);
}
}
a++;
}
b++;
}

for (int y = 0; y < 31; y++)
{
for (int x = 0; x < 40; x++)
{
Rectangle img1 = new Rectangle(x * 32, y * 32,32 ,32);
Rectangle img2 = new Rectangle(0, 0, 32, 32);
buf.DrawImage(bufferImage, img1, img2 ,GraphicsUnit.Pixel);
}
}

//ペンの破棄する
brush1.Dispose();
brush2.Dispose();
}



//描画処理関係
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
//グラフィック
Graphics g = e.Graphics;
//g.Clear(Color.White);
//表にすべて表示する
g.DrawImage(bufferImage, 0, 0);

}

}

}
2006/08/08(Tue) 00:13:00 編集(投稿者)
2006/08/08(Tue) 00:08:24 編集(投稿者)
2006/08/07(Mon) 23:56:07 編集(投稿者)
2006/08/07(Mon) 23:56:04 編集(投稿者)
2006/08/07(Mon) 23:55:06 編集(投稿者)

■No17045に返信(mimiさんの記事)
> ではコード表示しますね
> 簡単に言うとオフスクリーンの一番右上端から32*32の大きさで描画処理して
> その書いたオフスクリーンの画像を元にまた同じオフスクリーンに
> 描画したいのです。
>
Frame Work2.0 なら
 BufferedGraphicsContextクラス
 関連を使う手があります。
 私はVBがメインなのですが。
 バッファの画像をコントロールのバックバッファ?に描いて
 それを、BufferedGraphics.Render メソッドを用いて
 表に表示させると言う方法です。
 ヘルプにサンプルがあったです。
 利用してみるのも手だと思います。

 画像の補間モードを低質にしておくのも早くする一つの手です。
 

 
> 簡単に言うとオフスクリーンの一番右上端から32*32の大きさで描画処理して
> その書いたオフスクリーンの画像を元にまた同じオフスクリーンに
> 描画したいのです。

それより、32x32 のオフスクリーンを作成&描画したものを、必要サイズのオフスクリーンに DrawImage() する方が簡単じゃないですか?

それに、32x32 のパターンが頻出するなら ImageList に登録しておくもよし、です。
そうですか32*32のオフスクリーンを作り
もう一つのオフスクリーンに作ったほうがいいのですね
どうしてそうしたのかというとまたオフスクリーンを作ると
メモリ不足になるかなと思ったので1つのオフスクリーンで何とかしようとおもいました。
> どうしてそうしたのかというとまたオフスクリーンを作ると
> メモリ不足になるかなと思ったので1つのオフスクリーンで何とかしようとおもいました。

無限の資源ではないので節約するのは悪いことではありませんが、32x32 程度なら大したメモリ量ではありません。

一方、表示領域サイズ=大抵はフォームのクライアント領域サイズのオフスクリーンは、かなり多量のメモリを消費するので、これは大切に使いましょう。
そうですかありがとうございます
でも実際のところはやはり
オフスクリーンに同じオフスクリーンの内容をコピーする
ということはできないんでしょうか?
> オフスクリーンに同じオフスクリーンの内容をコピーする
> ということはできないんでしょうか?

出来そうに思いますけど?

「出来なかった」とは、以前示されたコードで具体的にどんな問題が生じたのですか?

僕はサポセンじゃないので、「実行してみろ」ってことならお断りです。
まず先ほどのサンプルを実行すると
フォームが表示されるまでがすごい時間が掛かります
そして上のサンプルではオフスクリーンの左上端に描画して
それを元に同じオフスクリーンを埋め尽くすようにしていますが
左上端だけに描画されて埋め尽くされません。
つまりオフスクリーンに書き込むことはできますが
オフスクリーンに同じオフスクリーンの内容はやはり無理でした。
■No17071に返信(mimiさんの記事)

mimiさん こんにちは エツです。


> まず先ほどのサンプルを実行すると
> フォームが表示されるまでがすごい時間が掛かります
> そして上のサンプルではオフスクリーンの左上端に描画して
> それを元に同じオフスクリーンを埋め尽くすようにしていますが
> 左上端だけに描画されて埋め尽くされません。
> つまりオフスクリーンに書き込むことはできますが
> オフスクリーンに同じオフスクリーンの内容はやはり無理でした。

まず先ほどのサンプルとは No.17045 で宜しいのでしょうか?
失礼ですがこのコードはちゃんと動作するのですか?
それとも、動作するか解らないから、見て欲しいとの事ですか?

私の経験からすると、うまく動作しない場合は大概コードが間違っています。

あなたのしたい内容が理解できないので意見を述べるのはいけない事ですが、参考になればと思い投稿します。
(速度を速めたいのは解るがコードと実際の描画イメージとの関連=コード内容が判らない)

ぱっと見た感じでコード内の次の部分が意味が解りません。

>for (int y = 0; y < 8; y++)
>{
>for (int x = 0; x < 8; x++)
>{
>if (b % 2 == 0)
>{
>//偶数なら緑ブラシ
>if (a % 2 == 0)
>{
>buf.FillRectangle(brush1, x * 4, y * 4, 4, 4);
>}
>//奇数なら白ブラシ
>else
>{
>buf.FillRectangle(brush2, x * 4, y * 4, 4, 4);
>}
>}
>else
>{
>//偶数なら白ブラシ
>if (a % 2 == 0)
>{
>buf.FillRectangle(brush2, x * 4, y * 4, 4, 4);
>}
>//奇数なら緑ブラシ
>else
>{
>buf.FillRectangle(brush1, x * 4, y * 4, 4, 4);
>}
>}
>a++;
>}
>b++;
>}
>
>for (int y = 0; y < 31; y++)
>{
>for (int x = 0; x < 40; x++)
>{
>Rectangle img1 = new Rectangle(x * 32, y * 32,32 ,32);
>Rectangle img2 = new Rectangle(0, 0, 32, 32);
>buf.DrawImage(bufferImage, img1, img2 ,GraphicsUnit.Pixel);
>}
>}

直感的ですが、これではなあ ... という気がします。
勿論正しいかもしれません。
コード内容に自信が無くコードの正誤を聞きたいのなら、もっとコードの1行毎の説明(何をしているコードか)が必要です。

コードに自信があれば、私の余計なお節介と笑ってください。
実行は出来ます
ただ自分の思ったとおりになりません
ちなみに上のソースが何をしているかと言うと
オフスクリーンに4*4のサイズで色を交互に色を塗ります
つまりこのように網目のように4*4ピクセルずつ塗ります
最終的に32*32にします
■□■□
□■□■
あとはこれを元に最大化状態になってもすべて塗りつぶせるよう
同じオフスクリーンに今書いた網目を転送してすべて塗りつぶします
あとはフォームがすべて網目状態で塗りつぶされるようにしたいのです
つまりフォームを表示すればすべて塗りつぶし状態にされたいのです
オフスクリーンと別々につくったときないです。
2006/08/09(Wed) 21:06:02 編集(投稿者)

■No17075に返信(mimiさんの記事)

どこまでお役にたてるかわかりませんが。

> 実行は出来ます
> ただ自分の思ったとおりになりません
> ちなみに上のソースが何をしているかと言うと
> オフスクリーンに4*4のサイズで色を交互に色を塗ります
> つまりこのように網目のように4*4ピクセルずつ塗ります

始めに上記内容の部分だけ確認します。

for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
{
if (b % 2 == 0)
{
//偶数なら緑ブラシ
if (a % 2 == 0)
{
buf.FillRectangle(brush1, x * 4, y * 4, 4, 4);
}
//奇数なら白ブラシ
else
{
buf.FillRectangle(brush2, x * 4, y * 4, 4, 4);
}
}
else
{
//偶数なら白ブラシ
if (a % 2 == 0)
{
buf.FillRectangle(brush2, x * 4, y * 4, 4, 4);
}
//奇数なら緑ブラシ
else
{
buf.FillRectangle(brush1, x * 4, y * 4, 4, 4);
}
}
a++;
}
b++;
}
return;  // ここまでオフスクリーン処理が完了 テストのため以後の処理は打ち切る。return;で抜けると表示できるはずです。

ここまでの処理時間と表示内容は予定通りか確認してください。


(注意)
//ペンの破棄、グラフィックの破棄は必要ですがテストの為割愛しています
brush1.Dispose();
brush2.Dispose();
buf.Dispose();
2006/08/09(Wed) 21:17:58 編集(投稿者)

そこまでの処理は予定通り
実行できます。
またそこまでの処理と
さっきのプログラムの結果が同じになり
表示されるまでが極端に遅くなります
結果はどちらも32*32サイズで4*4ピクセルの
青と白が交互に塗りつぶされた網目が表示されます
■No17077に返信(mimiさんの記事)
> そこまでの処理は予定通り
> 実行できます。

そうすると次の部分が悪いわけですが。
ちなみに最後に buf.Dispose(); も入れて下さいね。


for (int y = 0; y < 31; y++)
{
for (int x = 0; x < 40; x++)
{
Rectangle img1 = new Rectangle(x * 32, y * 32,32 ,32);
Rectangle img2 = new Rectangle(0, 0, 32, 32);
buf.DrawImage(bufferImage, img1, img2 ,GraphicsUnit.Pixel);
}
}

//ペンの破棄する
brush1.Dispose();
brush2.Dispose();
//グラフィックの破棄 (追加)
buf.Dispose();
}


さて この部分は一体なにをしているのでしょうか?
オフスクリーン(bufferImage)の一部を抜き出して同じオフスクリーン(bufferImage)に描画している。
別の作成したオフスクリーンに描画なら、コピーを作っているという意味はありますが、コピーなど必要ないでしょう。
この部分の動作を説明してください。
この部分を追加するとおかしくなります
まずフォームが表示されるまでが極端に遅く
32*32の網目の画像しか表示されません
自分としてはクライアント領域すべてにこの
網目を表示させたいのです
またどうしてこのようなことをしているのかと言うと
4*4のサイズの塗りつぶしをオフスクリーンすべてに行うと
遅くなってしまうからわざわざ32*32の大きさの網目の画像を作り
それをオフスクリーンにすべてコピーしたいのです
別々にオフスクリーンと作れば問題なく出来るし動作も速いです
また今回は32*32と転送もとの画像が小さいですがおおきいと
たとえば300*300の画像だと
オフスクリーンを300*300と最大化したときのクライアント領域分の
オフスクリーンが必要になります1400*1000ぐらいになるので
かなりメモリが消費するから1つのオフスクリーンでコピーしたいわけです。
■No17079に返信(mimiさんの記事)
> この部分を追加するとおかしくなります
> まずフォームが表示されるまでが極端に遅く
> 32*32の網目の画像しか表示されません
> 自分としてはクライアント領域すべてにこの
> 網目を表示させたいのです
> またどうしてこのようなことをしているのかと言うと
> 4*4のサイズの塗りつぶしをオフスクリーンすべてに行うと
> 遅くなってしまうからわざわざ32*32の大きさの網目の画像を作り
> それをオフスクリーンにすべてコピーしたいのです
> 別々にオフスクリーンと作れば問題なく出来るし動作も速いです
> また今回は32*32と転送もとの画像が小さいですがおおきいと
> たとえば300*300の画像だと
> オフスクリーンを300*300と最大化したときのクライアント領域分の
> オフスクリーンが必要になります1400*1000ぐらいになるので
> かなりメモリが消費するから1つのオフスクリーンでコピーしたいわけです。


おかしい部分は後で考えるとして
オフスクリーンを1400*1000として、No.17076 の方法で4*4のサイズの塗りつぶしをした場合どのくらいの時間が掛かりますか?
実際欲しいのは4*4のサイズの塗りつぶしでいいのですね。
■No17080に返信(エツさんの記事)

>
> おかしい部分は後で考えるとして
> オフスクリーンを1400*1000として、No.17076 の方法で4*4のサイズの塗りつぶしをした場合どのくらいの時間が掛かりますか?
> 実際欲しいのは4*4のサイズの塗りつぶしでいいのですね。
>

これを実行してみました。
//ペンの作成
Brush brush1 = new SolidBrush(Color.Blue);
Brush brush2 = new SolidBrush(Color.White);


for (int yy=0;yy<bufferImage.Size.Height; yy+=8)
{
for (int xx=0;xx<bufferImage.Size.Width; xx+=8)
{

int a = 0;
int b = 0;
for (int y = yy; y < yy+8; y++)
{
for (int x = xx; x < xx+8; x++)
{
if (b % 2 == 0)
{
//偶数なら緑ブラシ
if (a % 2 == 0)
{
buf.FillRectangle(brush1, x * 4, y * 4, 4, 4);
}
//奇数なら白ブラシ
else
{
buf.FillRectangle(brush2, x * 4, y * 4, 4, 4);
}
}
else
{
//偶数なら白ブラシ
if (a % 2 == 0)
{
buf.FillRectangle(brush2, x * 4, y * 4, 4, 4);
}
//奇数なら緑ブラシ
else
{
buf.FillRectangle(brush1, x * 4, y * 4, 4, 4);
}
}
a++;
}
b++;
}
}
}

return;

実行速度も まあまあこんなもんかと
■No17081に返信(エツさんの記事)
> ■No17080に返信(エツさんの記事)
>

私のコードに誤りがありました。

for (int yy=0;yy<bufferImage.Size.Height; yy+=8)
{
for (int xx=0;xx<bufferImage.Size.Width; xx+=8)
{
の部分は

for (int yy=0;yy<bufferImage.Size.Height/4; yy+=8)
{
for (int xx=0;xx<bufferImage.Size.Width/4; xx+=8)
{

となるのですね。
失礼しました。



>
> これを実行してみました。
> //ペンの作成
> Brush brush1 = new SolidBrush(Color.Blue);
> Brush brush2 = new SolidBrush(Color.White);
>
>
> for (int yy=0;yy<bufferImage.Size.Height; yy+=8)
> {
> for (int xx=0;xx<bufferImage.Size.Width; xx+=8)
> {
>
> int a = 0;
> int b = 0;
> for (int y = yy; y < yy+8; y++)
> {
> for (int x = xx; x < xx+8; x++)
> {
> if (b % 2 == 0)
> {
> //偶数なら緑ブラシ
> if (a % 2 == 0)
> {
> buf.FillRectangle(brush1, x * 4, y * 4, 4, 4);
> }
> //奇数なら白ブラシ
> else
> {
> buf.FillRectangle(brush2, x * 4, y * 4, 4, 4);
> }
> }
> else
> {
> //偶数なら白ブラシ
> if (a % 2 == 0)
> {
> buf.FillRectangle(brush2, x * 4, y * 4, 4, 4);
> }
> //奇数なら緑ブラシ
> else
> {
> buf.FillRectangle(brush1, x * 4, y * 4, 4, 4);
> }
> }
> a++;
> }
> b++;
> }
> }
> }
>
> return;
>
> 実行速度も まあまあこんなもんかと
>
>
>
> まず先ほどのサンプルを実行すると
> フォームが表示されるまでがすごい時間が掛かります

と、その前に最終目標を確認させてください。

・フォームの背景を特定のパターンで高速に塗りつぶしたい
・フォームに古典的なRGPのマップのような、特定のパターンの任意の組み合わせからなる画像を描画したい

のどちらでしょう?

前者であれば、オフスクリーンを使う必要はありません。

オンザフライで Bitmap を作成して、それを Form.BackgroundImage に設定してやれば、十分な速度で描画してくれるはずです。
(最初に確認しておくべきでした)
2006/08/10(Thu) 14:20:18 編集(投稿者)
2006/08/10(Thu) 12:24:28 編集(投稿者)

■No17080に返信(エツさんの記事)


>
> おかしい部分は後で考えるとして

for (int y = 0; y < 31; y++)
{
for (int x = 0; x < 40; x++)
{
Rectangle img1 = new Rectangle(x * 32, y * 32,32 ,32);
Rectangle img2 = new Rectangle(0, 0, 32, 32);
buf.DrawImage(bufferImage, img1, img2 ,GraphicsUnit.Pixel);
}
}

この部分ですが、コード的にはこのように書いても問題ない気がしますが
実行すると御指摘の通り上手く動作しませんね。
理由は不明ですがこのコードでは本レスのタイトルの
’オフスクリーンの内容を同じオフスクリーンにコピーする’ が不可となり、意図する動作にならないですね。
別イメージからこのコードでコピーすると問題ないようです。


但し別のコードで書けば’オフスクリーンの内容を同じオフスクリーンにコピーする’ は可能かもしれません。
2006/08/10(Thu) 18:10:19 編集(投稿者)

>buf.DrawImage(bufferImage, img1, img2 ,GraphicsUnit.Pixel);

本当ですね。Graphicsオブジェクトの作成元のイメージで描画しようとすると,
エラーがでるわけでもなく,何も描画されませんね。不思議です。

次のようなコードだと問題なく描画され,また速度もそこそこにでるようです。

namespace WindowsApplication1
{
    public partial class Form1 : Form
    {
        private Image bufferImage = new Bitmap(1400, 1000);

        public Form1()
        {
            InitializeComponent();
            this.Load += new EventHandler(Form1_Load);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            BackGraund();
        }

        private void BackGraund()
        {
            Image UnitImage = new Bitmap(32, 32);
            Graphics gUnit = Graphics.FromImage(UnitImage);
            Brush brush1 = new SolidBrush(Color.Blue);
            Brush brush2 = new SolidBrush(Color.White);
            for (int y = 0; y < 8; y++)
            {
                for (int x = 0; x < 8; x++)
                {
                    gUnit.FillRectangle(y % 2 == 0 ? x % 2 == 0 ? brush1 : brush2 : x % 2 == 0 ? brush2 : brush1, x * 4, y * 4, 4, 4);
                }
            }
            brush2.Dispose();
            brush1.Dispose();
            gUnit.Dispose();
            Graphics gBuf = Graphics.FromImage(bufferImage);
            for (int y = 0; y < 31; y++)
            {
                for (int x = 0; x < 40; x++)
                {
                    gBuf.DrawImage(UnitImage, x * 32, y * 32);
                }
            }
            gBuf.Dispose();
            UnitImage.Dispose();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            e.Graphics.DrawImage(bufferImage, 0, 0);
        }
    }
}
みなさんありがとうございます

渋木宏明(ひどり) さんへ
なるほどBackgroundImageを使えばいいんですね

エツさんへ
やはりオフスクリーンの内容を同じオフスクリーンにコピーするは
できないですね。

YASへ
オフスクリーンを2つ使う方法なら可能なんですけどね

みなさま本当に感謝しますありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板