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

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

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

Re[15]: Imageクラスの継承


(過去ログ 18 を表示中)

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

■7288 / inTopicNo.1)  Imageクラスの継承
  
□投稿者/ ps8rX (1回)-(2007/09/03(Mon) 14:19:15)

分類:[C#] 

開発環境
VS2005 C#

はじめまして。C#初心者です。

Windowsアプリケーションで画像編集ソフトを作っています。
画素にBitmapのGetPixel()を使ってアクセスしているのですが、
パソコンにパンチを入れたくなるくらい遅いのです。

なので、Imageクラスを派生して、Bitmap.LockBitsを使用してBitmapオブジェクト的なものを
実装したいのです。

そこで、Bitmapのメタデータと、クラスの継承が載っているサイトを参考に
public sealed class ExBitmap : Image
{
  public ExBitmap(Image original) : base (){}
    //...以下、実装予定。
}

以上のようにコードを打ってみたのですが、
「型 'System.Drawing.Image' のコンストラクタが定義されていません。」
と、エラーが出てしまいます。

この場合、どのように実装すればいいのでしょうか?
お願いいたします。

引用返信 編集キー/
■7290 / inTopicNo.2)  Re[1]: Imageクラスの継承
□投稿者/ Hongliang (183回)-(2007/09/03(Mon) 14:26:43)
Hongliang さんの Web サイト
Image クラスは、ビットマップイメージとベクタイメージを統一的に扱うためのクラスです。
ですので、当然ながら LockBits メソッドを持っていません。ビットマップイメージじゃないと意味がないメソッドですからね。
ですから、Image から直接派生して LockBits で操作するクラスってのは、設計がおかしいと言うことになります。

でもそういうのは派生させるよりユーティリティクラス的に外部から操作した方がいいと思うなぁ。
引用返信 編集キー/
■7293 / inTopicNo.3)  Re[2]: Imageクラスの継承
□投稿者/ ps8rX (2回)-(2007/09/03(Mon) 14:50:08)
2007/09/03(Mon) 15:01:53 編集(投稿者)
>■No7290 (Hongliang さん) に返信
> Image クラスは、ビットマップイメージとベクタイメージを統一的に扱うためのクラスです。
> ですので、当然ながら LockBits メソッドを持っていません。ビットマップイメージじゃないと意味がないメソッドですからね。
> ですから、Image から直接派生して LockBits で操作するクラスってのは、設計がおかしいと言うことになります。
> 
> でもそういうのは派生させるよりユーティリティクラス的に外部から操作した方がいいと思うなぁ。
回答ありがとうございます。
実は、ttp://junki.lix.jp/csgr/005ColorDataAccess3.htmのサイトを参考に
/// <summary>高速ビットマップ機能(暫定)</summary>
public class ExBitmap : IDisposable
{
        private bool _flagDispose = false;
        private Bitmap _Bitmap;
        private BitmapData _BitmapData;
        private IntPtr _Pointer;
        private int _Stride;
        private int _DataSize;
        private byte[] _ColorData;

        public Bitmap GetBitmap() { return _Bitmap; }
        public ExBitmap(Bitmap bitmap) { _Bitmap = bitmap; Main(); }
        public ExBitmap(int width, int height) { _Bitmap = new Bitmap(width, height); Main(); }
        // TODO: これだと、Aチャンネルにアクセスできないらしい...? public ExBitmap(Image image) { _Bitmap =new Bitmap(image); }
        private void Main()
        {
                _BitmapData = _Bitmap.LockBits(new Rectangle(0, 0, _Bitmap.Width, _Bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                _Pointer = _BitmapData.Scan0;
                _Stride = _BitmapData.Stride;
                _DataSize = _Stride * _Bitmap.Height;
                _ColorData = new byte[_DataSize];
                // ARGBデータのメモリコピーを可能にします。
                System.Runtime.InteropServices.Marshal.Copy(_Pointer, _ColorData, 0, _DataSize);
        }

        public Color GetPixel(int x, int y)
        {
                int ix = (_Stride * y) + (x * 4);
                byte A = _ColorData[ix + 3];
                byte R = _ColorData[ix + 2];
                byte G = _ColorData[ix + 1];
                byte B = _ColorData[ix + 0];
                return Color.FromArgb(A, R, G, B);
        }

        public void SetPixel(int x, int y, Color col)
        {
                int ix = (_Stride * y) + (x * 4);
                _ColorData[ix + 3] = col.A;
                _ColorData[ix + 2] = col.R;
                _ColorData[ix + 1] = col.G;
                _ColorData[ix + 0] = col.B;
        }

        protected virtual void Dispose(bool flag)
        {
                if (!_flagDispose)
                {
                        if (flag)
                        {
                                // ARGBデータの転送を行います。
                                System.Runtime.InteropServices.Marshal.Copy(_ColorData, 0, _Pointer, _DataSize);
                                _Bitmap.UnlockBits(_BitmapData);
                        }
                        this._flagDispose = true;
                }
        }

        public void Dispose()
        {
                Dispose(true);
                GC.SuppressFinalize(this);
        }

        ~ExBitmap()
        {
                Dispose(false);
        }
}
を実装してみました。
これで、かなりの速度で画像データにアクセスできます。
しかし、SetPixel()でアクセスした画像を得るには、
GetBitmap()を通さないと画像データが受け取れないので、
Imageクラスから派生したBitmapオブジェクト的な感じの
実装をしたいと思い質問させていただきました。

上記のような実装ってできないのでしょうか?

引用返信 編集キー/
■7296 / inTopicNo.4)  Re[3]: Imageクラスの継承
□投稿者/ IIJIMAS (18回)-(2007/09/03(Mon) 15:12:33)
> しかし、SetPixel()でアクセスした画像を得るには、
> GetBitmap()を通さないと画像データが受け取れないので、
> Imageクラスから派生したBitmapオブジェクト的な感じの
> 実装をしたいと思い質問させていただきました。
>
> 上記のような実装ってできないのでしょうか?

さらなBitmapインスタンスを作成して、そこから
Graphics.FromImage メソッド
http://msdn2.microsoft.com/ja-jp/library/system.drawing.graphics.fromimage(VS.80).aspx
でGraphicsのオブジェクト得て、
Graphics.DrawImage メソッド
http://msdn2.microsoft.com/ja-jp/library/system.drawing.graphics.drawimage(VS.80).aspx
でもとのImageをそこに描画してしまえば、その内部のBitmapができると思います。
引用返信 編集キー/
■7302 / inTopicNo.5)  Re[4]: Imageクラスの継承
□投稿者/ Hongliang (184回)-(2007/09/03(Mon) 15:56:41)
Hongliang さんの Web サイト
> さらなBitmapインスタンスを作成して、そこから
> Graphics.FromImage メソッド
> http://msdn2.microsoft.com/ja-jp/library/system.drawing.graphics.fromimage(VS.80).aspx
> でGraphicsのオブジェクト得て、
> Graphics.DrawImage メソッド
> http://msdn2.microsoft.com/ja-jp/library/system.drawing.graphics.drawimage(VS.80).aspx
> でもとのImageをそこに描画してしまえば、その内部のBitmapができると思います。

それは論点が違うと思いますが……。
Image オブジェクトから Bitmap オブジェクトがほしいなら Bitmap(Image) コンストラクタを使えば基本的に十分です。
// 元オブジェクトのクローンである点には気をつける必要がありますが。


一番の問題は、LockBits している間はその Bitmap オブジェクトの一部メソッドが阻害されると言う点です。また、UnlockBits するまではそのポインタに適用した変更が Bitmap オブジェクトに反映されません。
Image から派生させたクラスを作れたとして、そのインスタンス生成時に LockBits して破棄時に UnlockBits するような構造だと実質使い物になりません。
かといって、毎回 LockBits/UnlockBits するような構造にするぐらいなら GetPixel/SetPixel した方がマシです。
必要な間だけロックするようにすればいい、と言うのは Bitmap クラスの実装と全く同じです。別クラスで表現する意味がありません。
BitmapData から任意の座標を計算するのが面倒なら、そういうメソッドを用意してやればいいだけで、それは派生クラスでなくても可能です。

てことで、結局 ExBitmap : IDisposable みたいな実装が妥当な形になります。
// これはこれで色々問題があるようですが……まあ自分で使う分には。

以上、取り敢えず実装的な面から。オブジェクト指向的意味論からも否定できそうですが。
引用返信 編集キー/
■7304 / inTopicNo.6)  Re[5]: Imageクラスの継承
□投稿者/ ps8rX (3回)-(2007/09/03(Mon) 16:16:40)
2007/09/03(Mon) 16:18:21 編集(投稿者)

Hongliang さん、 IIJIMAS さん回答ありがとうございます。

>さらなBitmapインスタンスを作成して、そこから
>Graphics.FromImage メソッド
>http://msdn2.microsoft.com/ja-jp/library/system.drawing.graphics.fromimage(VS.80).aspx
>でGraphicsのオブジェクト得て、
>Graphics.DrawImage メソッド
>http://msdn2.microsoft.com/ja-jp/library/system.drawing.graphics.drawimage(VS.80).aspx
>でもとのImageをそこに描画してしまえば、その内部のBitmapができると思います。

すいません、ちょっと意味がわからなかったですorz.

えっとやりたいことは、ExBitmap ≒ Bitmap的なことです。
Bitmapは、
Bitmap bmp = new Bitmap(ほにゃらら);
Bitmap = bmpですが、
ExBitmapは、
using(ExBitmap exb = new ExBitmap(ほにゃらら));
Bitmap = exb.GetBitmap()です。
これを、Bitmap = ExBitmap的な感じ?(Bitmap = exb)
にしたいと...

説明下手ですいません。。。
#自分でもわからなくなってきちゃった...orz

引用返信 編集キー/
■7306 / inTopicNo.7)  Re[5]: Imageクラスの継承
□投稿者/ IIJIMAS (19回)-(2007/09/03(Mon) 16:24:53)
No7302 (Hongliang さん) に返信
>>さらなBitmapインスタンスを作成して、そこから
>>Graphics.FromImage メソッド
>>http://msdn2.microsoft.com/ja-jp/library/system.drawing.graphics.fromimage(VS.80).aspx
>>でGraphicsのオブジェクト得て、
>>Graphics.DrawImage メソッド
>>http://msdn2.microsoft.com/ja-jp/library/system.drawing.graphics.drawimage(VS.80).aspx
>>でもとのImageをそこに描画してしまえば、その内部のBitmapができると思います。
>
> それは論点が違うと思いますが……。
> Image オブジェクトから Bitmap オブジェクトがほしいなら Bitmap(Image) コンストラクタを使えば基本的に十分です。
> // 元オブジェクトのクローンである点には気をつける必要がありますが。

そうですね、コンストラクタでよかったのですね。。。

> 必要な間だけロックするようにすればいい、と言うのは Bitmap クラスの実装と全く同じです。別クラスで表現する意味がありません。
> BitmapData から任意の座標を計算するのが面倒なら、そういうメソッドを用意してやればいいだけで、それは派生クラスでなくても可能です。

私も派生クラスを作るのは無意味だと思います。

> てことで、結局 ExBitmap : IDisposable みたいな実装が妥当な形になります。
> // これはこれで色々問題があるようですが……まあ自分で使う分には。
>
> 以上、取り敢えず実装的な面から。オブジェクト指向的意味論からも否定できそうですが。

ぜひ、教えてください。

No7304 (ps8rX さん) に返信
> 2007/09/03(Mon) 16:18:21 編集(投稿者)
>
> Hongliang さん、 IIJIMAS さん回答ありがとうございます。
>
> >さらなBitmapインスタンスを作成して、そこから
> >Graphics.FromImage メソッド
> >http://msdn2.microsoft.com/ja-jp/library/system.drawing.graphics.fromimage(VS.80).aspx
> >でGraphicsのオブジェクト得て、
> >Graphics.DrawImage メソッド
> >http://msdn2.microsoft.com/ja-jp/library/system.drawing.graphics.drawimage(VS.80).aspx
> >でもとのImageをそこに描画してしまえば、その内部のBitmapができると思います。
>
> すいません、ちょっと意味がわからなかったですorz.

単にImage→Bitmapにする方法を書いただけです。コンストラクタでもよかったみたいですが。

> えっとやりたいことは、ExBitmap ≒ Bitmap的なことです。
> Bitmapは、
> Bitmap bmp = new Bitmap(ほにゃらら);
> Bitmap = bmpですが、
> ExBitmapは、
> using(ExBitmap exb = new ExBitmap(ほにゃらら));
> Bitmap = exb.GetBitmap()です。
> これを、Bitmap = ExBitmap的な感じ?(Bitmap = exb)
> にしたいと...
>
> 説明下手ですいません。。。
> #自分でもわからなくなってきちゃった...orz

Bitmapクラスでできないんですか。
引用返信 編集キー/
■7307 / inTopicNo.8)  Re[6]: Imageクラスの継承
□投稿者/ ps8rX (4回)-(2007/09/03(Mon) 16:37:41)
2007/09/03(Mon) 17:17:25 編集(投稿者)

#言ってるのが矛盾してるのと、書き間違いがあったので修正しました。

IIJIMASさん、回答ありがとうございます。
> Bitmapクラスでできないんですか。

BitmapクラスのSetPixel()はとっても遅いので、
派生クラスの作り方的なものを質問させていただきました。

最初は、Bitmapを派生して、ExSetPixel(),ExGetPixel()をやろうと
思いましたが、Bitmapクラスはシール型だったので、
基底クラスのImageクラスからBitmapオブジェクトに
似せて実装しようと考えました。

なので、BitmapとExBitmapには互換がないとつらいので
Bitmap ≒ ExBitmapになる実装がしたかったのです。
自分の技量と想像力ではExBitmap.GetBitmap()を実装するのが精一杯です。
何か、良い方法は無いのでしょうか?




引用返信 編集キー/
■7311 / inTopicNo.9)  Re[7]: Imageクラスの継承
□投稿者/ Hongliang (185回)-(2007/09/03(Mon) 18:55:57)
Hongliang さんの Web サイト
No7306 (IIJIMAS さん) に返信

> > てことで、結局 ExBitmap : IDisposable みたいな実装が妥当な形になります。
> > // これはこれで色々問題があるようですが……まあ自分で使う分には。
> >
> > 以上、取り敢えず実装的な面から。オブジェクト指向的意味論からも否定できそうですが。
>
> ぜひ、教えてください。

上で挙がっている ExBitmap の実装の問題点は、Dispose の呼び出しが必須なのにそれを強制できない点です。
Dispose の呼び出しを行わなかった場合、それまで ExBitmap.SetPixel で設定していた値が破棄されますが、このデバッグはなかなか骨ではないでしょうか。
ExBitmap.GetBitmap の呼び出しをもって UnlockBits を行い、以後 SetPixel/GetPixel の呼び出しは例外を投げるようにすべきでしょう(UnlockBits 直後にもう一度 LockBits する手もあるかもしれません)。
更に、Dispose の呼び出しを行わなかった場合(上記の修正を加えた場合は、Dispose または GetBitmap の呼び出しを行わなかった場合)、Bitmap オブジェクトがロックされたままになります。コンストラクタに Bitmap オブジェクトを渡した場合、深刻な問題です。必ずクローンを持つようにすればいいんですが、それではこのクラスの意義が薄れるでしょう。
これを解決するのはなかなか大変ですが、GCHandle でメンバの Bitmap/BitmapData を GC から保護し、ファイナライザから呼ばれる Dispose(false) でも UnlockBits することになるかな。十分な解決にはなりませんけど。
考え出すと切りがなさそうです。でも、private なヘルパクラスなら、Dispose が必ず実行される前提の実装もありだと思っています。

オブジェクト指向的には……色々考えてたはずですが吹っ飛んでしまいました。
車輪の再発明さえ否定しないならアリかなー。結局、Bitmap クラスと同じなのだし。
当初は Bitmap からの派生を考えていたので、理屈も考えられましたが。

// ま、現実問題としては Image はコンストラクタ非公開、Bitmap は sealed でどうしようもないわけですが。
// 更にはロックにはアンロックが必要と言う要求から、結局 Bitmap.LockBits/UnlockBits と同じ形にせざるを得ないとか。



No7307 (ps8rX さん) に返信
No7302 が回答になっていると思いますが、まだ釈然としない点がありますか?
結局、LockBits/UnlockBits のタイミングが任意に指定できないなら意味がないわけで、そしてそれは既に Bitmap クラスが実装しているそのものです。
確かに BitmapData を直接扱うのは面倒ですから、LockBits から UnlockBits までの面倒を見てくれるクラスはあったら便利でしょうけれども。

// 上記の通り、そもそも派生クラス作れませんしね。
引用返信 編集キー/
■7314 / inTopicNo.10)  Re[8]: Imageクラスの継承
□投稿者/ ps8rX (6回)-(2007/09/03(Mon) 19:38:46)
2007/09/03(Mon) 19:39:10 編集(投稿者)
Hongliang さん、回答ありがとうございます。

確かに、実装してて、何か不安になってくるクラスです。

記事を参考に実装↓
bool throwcheck;

public void GetBitmap()
{
    System.Runtime.InteropServices.Marshal.Copy(_ColorData, 0, _Pointer, _DataSize);
    _Bitmap.UnlockBits(_BitmapData);
    throwcheck = true;
    return _Bitmap; 
}
public void SetPixel(...)
{
    if (throwcheck) throw new Exception("データにアクセスできないよ");
    ...
}
こういうことでしょうか?
なんか違う感がある。。。


それと、質問の仕方がおかしかったです。
やりたかったこと(?)は、
Bitmapクラスの戻り値はBitmapです。(戻り値って言わないかも)
で、ExBitmapクラスの戻り値をBitmapにしたいのです。
/// <summary>色調反転</summary>
/// <param name="bmp">ソース</param>
/// <returns></returns>
public static Image ColorReverse(Bitmap bmp)
{
                                
        Color col;
        using (ImageAbility.ExBitmap exbmp1 = new ImageAbility.ExBitmap(bmp.Width, bmp.Height))
        using (ImageAbility.ExBitmap exbmp2 = new ImageAbility.ExBitmap(bmp))
        {
                for (int i = 0; i < bmp.Width; i++)
                {
                        for (int j = 0; j < bmp.Height; j++)
                        {
                                col = exbmp2.GetPixel(i, j);
                                exbmp1.SetPixel(i, j, Color.FromArgb(255 - col.R, 255 - col.G, 255 - col.B));
                        }
                }
                return exbmp1.GetBitmap();
                // ↑exbmp1.GetBitmap(); で画像データを得ているわけですが、
                // 通常、Bitmapで操作した場合、Bitmap bmp = new Bitmap(ほにゃらら);
                // return bmp;で画像を得られます。
                // これと同じように、return exbmp1; でBitmapが返ってくるようにしたいのです。
                // 自分の経験ではできなさそうですが、どうでしょうか?
        }
 }

#日本語ムツカシイ...

引用返信 編集キー/
■7316 / inTopicNo.11)  Re[7]: Imageクラスの継承
□投稿者/ 渋木宏明(ひどり) (328回)-(2007/09/03(Mon) 19:42:16)
渋木宏明(ひどり) さんの Web サイト
2007/09/03(Mon) 19:58:44 編集(投稿者)

> なので、BitmapとExBitmapには互換がないとつらいので

それは使い方次第です。

加工用に「Bitmap 的なもの」を保持しておいて、必要な時だけ「本物の Bitmap に変換」で十分使い物になると思いますよ。

「Bitmap 的なもの」を「Bitmap の上位互換なもの」にしようとすると、返って余分なものを数多く背負い込むようになって面倒です。(でした)

僕の場合、重要なのは「Bitmap とのそっくりさん度」ではなく、「必要十分に Bitmap とメンバの構成が似ていて、高速にピクセルを扱えること。そしてクラス実装が軽量であること」の方が重要だと判断したので

http://hidori.jp/downloads/junktest/TestPsedoBitmap-20060821.zip

のような実装になりました。

引用返信 編集キー/
■7320 / inTopicNo.12)  Re[9]: Imageクラスの継承
□投稿者/ 渋木宏明(ひどり) (329回)-(2007/09/03(Mon) 20:29:52)
渋木宏明(ひどり) さんの Web サイト
> return exbmp1.GetBitmap();
> // ↑exbmp1.GetBitmap(); で画像データを得ているわけですが、
> // 通常、Bitmapで操作した場合、Bitmap bmp = new Bitmap(ほにゃらら);
> // return bmp;で画像を得られます。
> // これと同じように、return exbmp1; でBitmapが返ってくるようにしたいのです。

「そう書ける」ことが、そんなに重要かなー?

Bitmap 派生クラスが作れない以上、暗黙のキャストで Bitmap を返すようにして誤魔化すくらいしか無いんじゃないかと。
でも、そういう使い方はよくないと思う>暗黙のキャスト

引用返信 編集キー/
■7321 / inTopicNo.13)  Re[10]: Imageクラスの継承
□投稿者/ ps8rX (7回)-(2007/09/03(Mon) 20:48:34)
2007/09/03(Mon) 20:51:26 編集(投稿者)
渋木宏明(ひどり) さん、回答ありがとうございます。

ソースコード、ありがとうございます。
参考になりましたm(_ _)m。

> 「そう書ける」ことが、そんなに重要かなー?
やっぱりBitmapクラスに極力、互換を持たせないと
Bitmapから始めた自分には、ちょっとつらいかなぁって...
今の自分の課題としては、「そう書ける」ことがかなり重要です。

そこで、ググってたら「インデクサでGet,Set」なるものを発見しましたが、
this[] の[]の部分をのぞいた感じ?にすればできるのではと、以下
public Bitmap this()
{
     get
     {
            System.Runtime.InteropServices.Marshal.Copy(_ColorData, 0, _Pointer, _DataSize);
            _Bitmap.UnlockBits(_BitmapData);
            return _Bitmap;
     }
}
エラーでしたダメでした...

引用返信 編集キー/
■7322 / inTopicNo.14)  Re[10]: Imageクラスの継承
□投稿者/ ps8rX (8回)-(2007/09/03(Mon) 20:50:06)
2007/09/03(Mon) 20:52:53 編集(投稿者)

重複してしまったため、本文削除
引用返信 編集キー/
■7324 / inTopicNo.15)  Re[11]: Imageクラスの継承
□投稿者/ 渋木宏明(ひどり) (330回)-(2007/09/03(Mon) 21:25:34)
渋木宏明(ひどり) さんの Web サイト
> やっぱりBitmapクラスに極力、互換を持たせないと
> Bitmapから始めた自分には、ちょっとつらいかなぁって...

全部のメンバなんか使います?

> 今の自分の課題としては、「そう書ける」ことがかなり重要です。

まぁ、その辺は感覚的なモンなんでなんとも。。。なんですが。

例えば、コレクションも「配列のようなもの」であって「配列ではないもの」なので

Hoge[] GetHogeArray()
{
List<hoge> list = new List<Hoge>();

list.Add(hoge1);
list.Add(hoge2);

return list.ToArray();
}

のように使うのが当たり前ですけど、これにも違和感を感じますか?

> そこで、ググってたら「インデクサでGet,Set」なるものを発見しましたが、

えーと、1個前に

> 暗黙のキャストで Bitmap を返すようにして誤魔化す

と書いたんですが、検索とかしてみませんでした?

http://tech.bbtune.com/csharp/items/3-18.html

とか。


引用返信 編集キー/
■7328 / inTopicNo.16)  Re[8]: Imageクラスの継承
□投稿者/ 渋木宏明(ひどり) (332回)-(2007/09/03(Mon) 22:55:30)
渋木宏明(ひどり) さんの Web サイト
>>なので、BitmapとExBitmapには互換がないとつらいので
>
> それは使い方次第です。
>
> 加工用に「Bitmap 的なもの」を保持しておいて、必要な時だけ「本物の Bitmap に変換」で十分使い物になると思いますよ。

あー、僕の場合は画像処理が目的だったんでピクセル操作「しか」しなかったんで十分だったんですが、ペイント系ツールみたいにピクセル操作と線描なんかが混在するようなアプリだとちょっと不便かもしれないですね。

そーすると、要件としては

・なるべく Bitmap そのままを持っていたい
・Bitmap のピクセル操作が遅いはカンベン

てことになるわけですか。

でもこれだけなら、「Bitmap クラス(あるいは Image クラス)の派生クラス」でなんとかしなければならないという理由は特にありませんね。
(その方が多少「美しい」かもしらんけど)

実際、Bitmap クラスの派生クラスが作れないのは既知だし、Image クラス派生から出発するのは利益よりも不利益の方が多い(多そうな)のは、既に指摘されている通りです。

てことから、この場合は「Bitmap.Lock() を一時的にロックしてピクセル操作をさせるためのヘルパクラス」を作った方が楽なんじゃないかなーと思います。

今ちょっと暇なんで、この後ご飯食べて寝てしまわなかったらサンプルくらい書くかも (^^;

引用返信 編集キー/
■7335 / inTopicNo.17)  Re[9]: Imageクラスの継承
□投稿者/ 渋木宏明(ひどり) (333回)-(2007/09/04(Tue) 01:57:48)
渋木宏明(ひどり) さんの Web サイト
> てことから、この場合は「Bitmap.Lock() を一時的にロックしてピクセル操作をさせるためのヘルパクラス」を作った方が楽なんじゃないかなーと思います。
> 
> 今ちょっと暇なんで、この後ご飯食べて寝てしまわなかったらサンプルくらい書くかも (^^;

こんな感じ。

http://hidori.jp/downloads/junktest/TestBitmapBits-20070904.zip

使い方は

using (BitmapBits bits = new BitmapBits(this.bitmap))
{
    for (int y = 0; y < this.bitmap.Height; y++)
    {
        for (int x = 0; x < this.bitmap.Width; x++)
        {
            bits.SetPixel(x, y, color);
        }
    }
}

とか。

引用返信 編集キー/
■7337 / inTopicNo.18)  Re[10]: Imageクラスの継承
□投稿者/ ps8rX (9回)-(2007/09/04(Tue) 06:56:27)
渋木宏明(ひどり)さん、回答ありがとうございます。

返答が遅くなって申し訳ありません。事情でネットが不定期に繋がらないので。

>全部のメンバなんか使います?

確かに、全部は使わないです。

>> 今の自分の課題としては、「そう書ける」ことがかなり重要です。

>まぁ、その辺は感覚的なモンなんでなんとも。。。なんですが。

>例えば、コレクションも「配列のようなもの」であって「配列ではないもの」なので

>Hoge[] GetHogeArray()
>{
>List<hoge> list = new List<Hoge>();

>list.Add(hoge1);
>list.Add(hoge2);

>return list.ToArray();
>}

>のように使うのが当たり前ですけど、これにも違和感を感じますか?
コレクションは、やったことが無かったので違和感どころか
何も感じませんでした...すいません。
これは、Hogeコレクションのhoge要素にhoge1とhoge2を追加する、
と理解しました。(n次元配列的な?違ってたらすいません。)


>> そこで、ググってたら「インデクサでGet,Set」なるものを発見しましたが、

>えーと、1個前に

>> 暗黙のキャストで Bitmap を返すようにして誤魔化す

>と書いたんですが、検索とかしてみませんでした?

>http://tech.bbtune.com/csharp/items/3-18.html

>とか。
言葉足らずでした。
キャストのやり方がわからなかったので、ほかのやり方を検索したら>「インデクサでGet,Set」
になりました。
教えていただいたサイトのやり方で、ExBitmap = Bitmapな感じになりました。
public static implicit operator Bitmap(ExBitmap exbitmap) { return exbitmap.GetBitmap(); }

>そーすると、要件としては

>・なるべく Bitmap そのままを持っていたい
>・Bitmap のピクセル操作が遅いはカンベン

>てことになるわけですか。
そうです。というか、Bitmapそのままと言っていい?(実はBitmapを持っているとGraphicsでDrawRectangleとか...)


>てことから、この場合は「Bitmap.Lock() を一時的にロックしてピクセル操作をさせるためのヘルパクラス」を作った方が楽なんじゃないかなーと思います。

> 今ちょっと暇なんで、この後ご飯食べて寝てしまわなかったらサンプルくらい書くかも (^^;

>こんな感じ。

>http://hidori.jp/downloads/junktest/TestBitmapBits-20070904.zip

>使い方は

>using (BitmapBits bits = new BitmapBits(this.bitmap))
>{
> for (int y = 0; y < this.bitmap.Height; y++)
> {
> for (int x = 0; x < this.bitmap.Width; x++)
> {
> bits.SetPixel(x, y, color);
> }
> }
>}

>とか。
ソースコードまで作成していただいて、本当に感謝です。
とても、参考になります。m(_ _)m

しかし、>「Bitmap.Lock() を一時的にロックしてピクセル操作をさせるためのヘルパクラス」
のように、ピクセル操作をさせるためのクラスなら、
ttp://hidori.jp/downloads/junktest/TestPsedoBitmap-20060821.zip
のソースでも、同じではないかと思いました。

振る舞いはBitmap、機能的には上位にしたいのが本音です。
で、>Bitmap 派生クラスが作れない以上、暗黙のキャストで Bitmap を返すようにして誤魔化すくらいしか無いんじゃないかと。
なのですが、
やっぱり、暗黙のキャストにすがるしかないのでしょうか?

>そういう使い方はよくないと思う>暗黙のキャスト


#プログラミングは楽しいけど、難しいorz
引用返信 編集キー/
■7341 / inTopicNo.19)  Re[11]: Imageクラスの継承
□投稿者/ 渋木宏明(ひどり) (335回)-(2007/09/04(Tue) 10:16:16)
渋木宏明(ひどり) さんの Web サイト
> >全部のメンバなんか使います?
>
> 確かに、全部は使わないです。

であれば、前に書いたように

> 必要十分に Bitmap とメンバの構成が似ていて

で我慢した方が余分なところで悩まなくて簡単だと思うんですけどねぇ。

> >例えば、コレクションも「配列のようなもの」であって「配列ではないもの」なので
(略)
> これは、Hogeコレクションのhoge要素にhoge1とhoge2を追加する、
> と理解しました。(n次元配列的な?違ってたらすいません。)

そこは枝葉のとこです。

メソッド内部でコレクションを使用しているわけですが、メソッドインターフェースが「配列を返す」になっているので「コレクションを返す」ことは出来ないのため、「ToArray() によって コレクションから配列を作成してそれを返している」んです。
これは、Bitmap を返すべき局面で ExBitmap を返すわけにはいかず、ExBitmap.GetBitmap() で Bitmap を取り出して返すケースと似ていませんでしたか?

> 教えていただいたサイトのやり方で、ExBitmap = Bitmapな感じになりました。
> public static implicit operator Bitmap(ExBitmap exbitmap) { return exbitmap.GetBitmap(); }

これは内部的には ExBitmap.GetBitmap() しているわけで、本質的には何も変わってないです。

前にも書きましたが、個人的には、暗黙キャストのこういう使い方は良くないと思います。

> しかし、>「Bitmap.Lock() を一時的にロックしてピクセル操作をさせるためのヘルパクラス」
> のように、ピクセル操作をさせるためのクラスなら、
> ttp://hidori.jp/downloads/junktest/TestPsedoBitmap-20060821.zip
> のソースでも、同じではないかと思いました。

使い道や取り回し方、向き・不向きが違います。

PsedoBitmap は、Bitmap から内部的に int 配列を作ってそれを操作するようになっています。GetPixel(), SetPixel() が操作する対象は int 配列なので非常に高速です。

その反面、int 配列を作ってしまったら Bitmap との関係は断ち切られてしまうため、表示等で Bitmap が必要になった時は ToBitmap() メソッドによって再度「Bitmap を作り出す」ねばなりません。これは比較的コストが高い操作です。

もう一方の BitmapBits は、BitmapBits を new すると同時にコンストラクタの引数で与えられた Bitmap を LockBits() して、BitmapBits を Dispose() する時に Bitmap を UnlockBits() します。

BitmapData が指すデータを直接操作するためピクセル操作の性能は PsedoBitmap を超えることはありませんが、Bitmap のデータを直接操作しているため、表示などの際に PsedoBitmap のように「Bitmap を作る」必要はありません。

結果として、延々とピクセル処理だけを行って結果を最終結果を表示するようなパターン(いわゆる画像処理など)では PsedoBitmap が、ほどほどの量のピクセル処理と図形描画などの処理が混在するパターン(いわゆるペイントツールなど)では BitmapBits の方が有利であると推察されます。

> やっぱり、暗黙のキャストにすがるしかないのでしょうか?

「書き方」にこだわるならそうなりますが、↑でも書いたように、僕はよくない使い方だと思います。

まぁ、修作とかの個人作品なら、自分が納得いくように書くのは止めません ;-)

引用返信 編集キー/
■7351 / inTopicNo.20)  Re[12]: Imageクラスの継承
 
□投稿者/ ps8rX (10回)-(2007/09/04(Tue) 12:32:05)
渋木宏明(ひどり)さん、回答ありがとうございます。

>> 教えていただいたサイトのやり方で、ExBitmap = Bitmapな感じになりました。
>> public static implicit operator Bitmap(ExBitmap exbitmap) { return exbitmap.GetBitmap(); }
>これは内部的には ExBitmap.GetBitmap() しているわけで、本質的には何も変わってないです。
まぁ、クラスの戻り値(?)がBitmapならそれでいいやぁと思ったので...

> PsedoBitmap は、Bitmap から内部的に int 配列を作ってそれを操作するようになっています。GetPixel(), SetPixel() が操作する対象は int 配列なので非常に高速です。
>
> その反面、int 配列を作ってしまったら Bitmap との関係は断ち切られてしまうため、表示等で Bitmap が必要になった時は ToBitmap() メソッドによって再度「Bitmap を作り出す」ねばなりません。これは比較的コストが高い操作です。
・PsedoBitmapは、int配列で操作するので非常に早い。
・しかし、配列が作成されると画素を配列で扱うため、
配列からBitmapを作り出さないといけない。これはコストが高い。


> もう一方の BitmapBits は、BitmapBits を new すると同時にコンストラクタの引数で与えられた Bitmap を LockBits() して、BitmapBits を Dispose() する時に Bitmap を UnlockBits() します。
>
> BitmapData が指すデータを直接操作するためピクセル操作の性能は PsedoBitmap を超えることはありませんが、Bitmap のデータを直接操作しているため、表示などの際に PsedoBitmap のように「Bitmap を作る」必要はありません。
・BitmapBitsは、与えられたBitmapをLockBits()で直接操作するので、Bitmapを作る必要がない。

> 結果として、延々とピクセル処理だけを行って結果を最終結果を表示するようなパターン(いわゆる画像処理など)では PsedoBitmap が、ほどほどの量のピクセル処理と図形描画などの処理が混在するパターン(いわゆるペイントツールなど)では BitmapBits の方が有利であると推察されます。
・画像処理系のピクセル処理は、BitmapBitsの方が有利。
つまり、画像処理ではBitmapBits(あるいは、BitmapBitsに似せて)を実装すればよい。
と言うことですよね?

上記の実装(風)で行こうと思います。


質問に回答していただいた みなさん、本当にありがとうございました。
これで、解決と致します。

#頭で「こう!」って決めつけたら、中々納得しないもんですね...>自分
解決済み
引用返信 編集キー/

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

管理者用

- Child Tree -