12/2 簡単なグラフィクス(3)


11/11の課題について


質問と回答

Q.
イメージの扱いで
public ImageTrans(String fileName){
      // 親クラスである Frameクラスのコンストラクタを
      // タイトル文字列を "ImageTrans"として呼ぶ.
    super("ImageTrans");
      // 現在の Toolkit を得て,getImageで PNG 形式のファイルを指定して,
      // イメージを得る.
    // インスタンス変数 fileNameへコンストラクタの引数 fileNameの代入
    this.fileName=fileName;
 
親クラスのコンストラクタを呼んだということは、"ImageTrans"という値を
親クラスのコンストラクタの引数に指定し、親クラスにあったメンバ変数をそ
の引数で初期化したということですよね。どこでfileNameオブジェクトがつく
られたのでしょうか?また、 thisは今扱われているオブジェクトを指している
のに、どこでもオブジェクトは扱われていないと思うのですが?
A.
TAの小田原です。

>  親クラスのコンストラクタを呼んだということは、"ImageTrans"という値
>  を親クラスのコンストラクタの引数に指定し、親クラスにあったメンバ変数
>  をその引数で初期化したということですよね。

はいその通りです。その結果、この場合ではフレームのタイトルバーに書かれ
る文字列が"ImageTrans"になります。

>  どこでfileNameオブジェクトがつくられたのでしょうか?

確認しておくと、fileNameというのはこのクラスが持っているインスタンス変
数です。そこで、

> this.fileName = fileName; 

という文でfileNameに値を代入しています。右辺のfileNameは、たまたま左辺
と同じ変数名ですが意味的には全く異なり、

> public ImageTrans(String fileName){

にあるようにコンストラクタの引数を表す変数にすぎません。

このコンストラクタは実際にmainの下の文で呼び出され、

>  ImageTrans frame=new ImageTrans(args[0]);

引数は args[0] となっているので、javaを実行するときの引数の文字列が
fileNameとして扱われることになります。

と確認だけで説明が終わってしまいそうですが、質問の答えになっているでしょ
うか…(;;

>  また、 thisは今扱われているオブジェクトを指しているのに、どこでもオ
>  ブジェクトは扱われていないと思うのですが?

コンストラクタの中でthisという変数が使われている場合、thisはそのコンス
トラクタで生成されるオブジェクトを指していると思って下さい。

ですから、この場合には

>  ImageTrans frame=new ImageTrans(args[0]);

で生成されたframeというオブジェクトを指しています。
したがって、this.fileNameというのは、frame.fileNameということだ、と理
解してよいと思います。

Q.
イメージから、ピクセルデータの取得で
int w=image.getWidth(ImageTrans.this);
int h=image.getHeight(ImageTrans.this);

はimageオブジェクトにgetWidthやgetHeightメソッドの参照を行い、メソッド
ではImageTrans.thisを使っていると思うのですが、imageはクラス変数(メン
バ変数?インスタンス変数?)であってオブジェクトではないのでは?また
ImageTrans.thisの意味がわかりません。ImageTransクラスの何でしょう?

System.err.println(w+","+h);
errの意味がわかりません。outと同じですか?

System.exit(1)
中身が0のときと何か違うのですか?
 
printPpmPixel(pixels[j * w + i]
ピクセルの配列は[h * w]ではないのですか?

 // ImageTransクラスのインスタンスを作る.ImageTrans frame=new
    ImageTrans(args[0]); args[0]が String型のfileName変数に代入されると
    いうことですか?このインスタンスを作るために、コンストラクタメソッ
    ドで

this.fileName=fileName
として、メンバ変数の値をfileName変数(args[0])によって初期化したのですか?

    int alpha = (pixel >> 24) & 0xff;
    int red   = (pixel >> 16) & 0xff;
    int green = (pixel >>  8) & 0xff;
    int blue  = (pixel      ) & 0xff;  
で、0xffとは何ですか?また、たとえばpixel >>  8、では、alphaとredの数も入ってしまうのでは?

このプログラムは、全体として、
1、 メインメソッド>コンストラクタ呼び出し
2、コンストラクタ
3、適宜paintメソッドが呼び出される

という構造ですか?コンストラクタはオブジェクトを作るために、メンバ変数
を初期化するものだと思っていたのですが、ここでは、メソッドのような役割
を果たしているのですか?
A.
 > イメージから、ピクセルデータの取得で
 >int w=image.getWidth(ImageTrans.this);
 >int h=image.getHeight(ImageTrans.this);
 >はimageオブジェクトにgetWidthやgetHeightメソッドの参照を行い、メソッド
 >ではImageTrans.thisを使っていると思うのですが、

 「正確にいうと,変数imageの指すImage型のオブジェクトに」ということになります.

 >imageはクラス変数(メン
 >バ変数?インスタンス変数?)であってオブジェクトではないのでは?また

 imageはインスタンス変数です.オブジェクト型の「変数」を「参照」する場合は,

・ 変数の内容が null の場合はNullPointer 例外が発生
・ 変数があるオブジェクトを指す時は,そのオブジェクトに対して操作

となります.

 >ImageTrans.thisの意味がわかりません。ImageTransクラスの何でしょう?

 良いところに気が付きました.あの部分は

1.ImageTransクラスの中(Inner class)の
2.  MouseAdapterのサブクラスの無名クラス

のメソッドmousePressedにあたります.ここで,2のインスタンスはthisで得ら
れますが,1のインスタンスを得るための記法として,ImageTrans.thisという
書き方があります.この部分は説明が必要でしたね.

 >System.err.println(w+","+h);
 >errの意味がわかりません。outと同じですか?

 これはUnixの文化ですが,プログラムの出力として標準出力と標準エラー出力
の2種類が用意されています.他のプログラムで処理をするためにファイル等に
出力したい場合などは,標準出力に,本来の出力ではなく,単にメッセージを
出したい場合は標準エラー出力に出します.この部分は途中経過を表示するだ
けが目的で,標準出力には生成される画像ファイル(PPMファイル)を出力したい
ので標準エラー出力に出しています.

>System.exit(1)
>中身が0のときと何か違うのですか?

 これも Unix 文化によるもので,あるコマンドがSystem.exit(0)で終了した時
 は,正常終了で System.exit(0以外の値)で終了した時は,何らかのエラーで
 終了したことを示します.多くのshellでは

echo $?

で,最後に実行したコマンドの終了ステータスが分かります.

 > printPpmPixel(pixels[j * w + i]
 > ピクセルの配列は[h * w]ではないのですか?

 ピクセルの配列の大きさは h * w あります.
jが0からh-1まで,iが0からw-1まで動くので,
j * w + i は0から(h-1)*w+(w-1) = h*w-1 まで動きます.

> // ImageTransクラスのインスタンスを作る.
>    ImageTrans frame=new ImageTrans(args[0]);
>args[0]が String型のfileName変数に代入されるということですか?

 args[0]によって指されている String型のオブジェクトがString型の
fileNameという引数に代入されるということです.

>このイン
>スタンスを作るために、コンストラクタメソッドで
>this.fileName=fileName
>として、メンバ変数の値をfileName変数(args[0])によって初期化したのですか?

 args[0]によって指されているString型のオブジェクトは,mainが呼ばれる前
に,java処理系によって作られている.

>    int alpha = (pixel >> 24) & 0xff;
>    int red   = (pixel >> 16) & 0xff;
>    int green = (pixel >>  8) & 0xff;
>    int blue  = (pixel      ) & 0xff;  
>で、0xffとは何ですか?また、たとえばpixel >>  8、では、alphaとredの数も入ってしまうのでは?

 0xffの「0x」は次に続くのが16進数であることを示しています.16進数でfは
15なので,0xffは15*16+15=255となります.0xffと 論理積(&)をとることは,
下位8ビットのみを残して,残りを0でクリアすることを意味します.たとえば,
greenを取るには,元のpixel データ

+--------+--------+--------+-------+
| alpha  | red    | green  | blue  |       
+--------+--------+--------+-------+

31 ----24|23----16|15-----8|7-----0

から,pixel>>8で

+--------+--------+--------+--------+
|00000000| alpha  | red    | green  |
+--------+--------+--------+--------+

31 ----24|23----16|15-----8|7-----0

としてから,&0xffで

+--------+--------+--------+--------+
|00000000|00000000|00000000| green  |
+--------+--------+--------+--------+

31 ----24|23----16|15-----8|7-----0

とします.

>このプログラムは、全体として、
>1、 メインメソッド>コンストラクタ呼び出し
>2、コンストラクタ
>3、適宜paintメソッドが呼び出される
>という構造ですか?

 そうです.

>コンストラクタはオブジェクトを作るために、メンバ変数
>を初期化するものだと思っていたのですが、ここでは、メソッドのような役割
>を果たしているのですか?

 コンストラクタはオブジェクトを初期化するためのものですが,オブジェクト
の初期化はFrameクラスのオブジェクトのように,入出力ともからむものの場合
は,メンバ変数の初期化以外の操作を伴う場合があります.

Q.
ImageTrans,ImageLens プログラムをそのままコンパイルして実行したら、上手
くいきません。どうしてでしょう?
A.
 エラーを見てみる必要がありますが,ecc.gifというgif形式のファイルがない
 ディレクトリで実行したということはありませんか?

Q.
 ピクセルデータからイメージの作成で
// ImageLensクラスのコンストラクタ
  String fileName;
  // (x,y)に大きさlensSize(50)のレンズを置いたイメージをshowImageにして,repaintする
  void transImage(int x, int y)

ImageLensクラスのコンストラクタなのにどうしてコンストラクタ名が
ImageLensでなく、transImageなのでしょう?

    int w=image.getWidth(this);
    int h=image.getHeight(this);
thisとは何ですか?

if(pixels==null || pixels.length< w*h)

まだpixels配列は作られていないのだから、pixels==null はわかるのですが、
配列の数なども決まっていなく、pixels.length< w*hの条件の意味がわかりま
せん。

      pixels=new int[w * h];
      showPixels=new int[w * h];

どうして配列を二つも作っているのですか?

 System.arraycopy(pixels,0,showPixels,0,w*h);
    for (int j = Math.max(0,y-lensSize); j < Math.min(h,y+lensSize); j++) {
      int dy=j-y;
      for (int i = Math.max(0,x-lensSize); i < Math.min(w,x+lensSize); i++) {
	int dx=i-x;
	double r=Math.sqrt((double)(dx*dx+dy*dy)/(double)(lensSize*lensSize));
	if(r<1.0){
	  showPixels[j*w+i]=pixels[(y+(int)(dy*r))*w+(x+(int)(dx*r))];

arraycopyの意味がわかりません。ここは全体として、配列の数だけピクセルを
並べているということですか?
A.
>  ピクセルデータからイメージの作成で
> // ImageLensクラスのコンストラクタ
>   String fileName;
>   // (x,y)に大きさlensSize(50)のレンズを置いたイメージをshowImageにして,repaintする
>   void transImage(int x, int y)
> ImageLensクラスのコンストラクタなのにどうしてコンストラクタ名が
> ImageLensでなく、transImageなのでしょう?

 失礼,コメントの位置が違っていました transImageはコンストラクタではな
 く通常のメソッドです.

>     int w=image.getWidth(this);
>     int h=image.getHeight(this);
> thisとは何ですか?

 クラスImageLensのオブジェクトです.

> if(pixels==null || pixels.length< w*h) 
>まだpixels配列は作られていない
> のだから、pixels==null はわかるのですが、配列の数なども決まっていなく、
> pixels.length< w*hの条件の意味がわかりません。

    int w=image.getWidth(this);
    int h=image.getHeight(this);

で得られる w, h の値はネットワークごしに画像を持って来ている途中などは,
最終的な画像の大きさではなく,途中までロードした部分の画像の大きさが返
ることがあります.そのため,一度 pixelsを確保しても足りなくなる恐れがあ
るので,チェックして以前確保した領域が足りない場合は,もう一度取り直し
ています.

>       pixels=new int[w * h];
>       showPixels=new int[w * h];
> どうして配列を二つも作っているのですか?

 講義でも説明したと思いますが,元のイメージに対応するのが pixelsで,レ
ンズ上に変形させてつくり出した画像がshowPixelsになります.

>  System.arraycopy(pixels,0,showPixels,0,w*h);
> arraycopyの意味がわかりません。ここは全体として、配列の数だけピクセル
> を並べているということですか?

 順序が逆になってしみましたが,arraycopyの意味は,「Vectorクラス」の中で,

>  なお,
>      int i;
>      for(i=0;i< lines.length;i++)
>	newLines[i]=lines[i];
>
>のように,配列から配列へのコピーは,Systemクラスの arraycopyメソッドを
>使って,以下のように書くことができる.
>
>      System.arraycopy(lines,0,newLines,0,lines.length);

と説明しています.

今日の課題

上のURLは,今日(12/2)の17:00 までは
Forbidden

You don't have permission to access /~ktanaka/programming03/kadai1202.html on this server.
とうメッセージが出てアクセ スできないはずである.17:00以降にも同様のエラーが出る時は,Shiftキーを 押しながら,再読み込み(Reload)を押してみること.

課題の締切りは12/16(火)の21時まで


次へ進む