// ロードするパッケージの宣言
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;

//
// 画像の拡大/縮小、反転処理アプレット FlipImageクラスの定義
//
public class FlipImage extends Applet implements ItemListener {
  Image original;       // 原画像
  ImagePanel imgPanel;  // 画像処理結果の表示用パネル
  Choice fitChoice, flipChoice;// 処理選択用チョイス

  public void init() {
    // 画像ファイルの読込
    original = getImage(getDocumentBase(), "Sample.jpg");
    // 画像を完全に読み込むまで待つ処理
    MediaTracker mt = new MediaTracker(this);
    mt.addImage(original, 0);
    try {
      mt.waitForAll();
    } catch (InterruptedException e ) {}
    //ここまで、画像ファイルの読込処理

    // 画像表示用パネルの生成
    imgPanel = new ImagePanel(original);

    // 拡大/縮小用チョイスの生成
    fitChoice = new Choice();
    fitChoice.addItem("Original Size");
    fitChoice.addItem("Double Size");

    // 反転処理用チョイスの生成
    flipChoice = new Choice();
    flipChoice.addItem("Original Image");
    flipChoice.addItem("Flip Horizontal");
    flipChoice.addItem("Flip Vertical");
    flipChoice.addItem("Rotate 90 deg.");
    flipChoice.addItem("Rotate 180 deg.");

    // パネル、チョイスの配置指定
    this.setLayout(new BorderLayout());
    Panel p = new Panel();
    p.add(new Label("View mode:"));
    p.add(fitChoice);
    p.add(new Label("Flip mode:"));
    p.add(flipChoice);
    add("North", p);
    add("Center", imgPanel);

    // チョイスのイベントリスナ設定
    fitChoice.addItemListener(this);
    flipChoice.addItemListener(this);
    // チョイスを追加するときは、イベントリスナを追加して、
    // 次の itemStateChanged()中にも、イベント処理を追加すること。
  } 

  // チョイスのイベント処理用メソッド
  public void itemStateChanged(ItemEvent e) {
    if(e.getSource() == fitChoice) { // 拡大/縮小用チョイスが選択された場合
      imgPanel.setViewMode(fitChoice.getSelectedIndex());
      imgPanel.flipImage();
    } else if(e.getSource() == flipChoice) { // 反転処理用チョイスが選択された場合
      imgPanel.setFlipMode(flipChoice.getSelectedIndex());
      imgPanel.flipImage();
    }
  }

  public void paint(Graphics g) {
    imgPanel.setSize( getSize().width, getSize().height );
    // 画像表示パネルのサイズをアプレットビューアのサイズに再設定
  }
}

//
// 画像表示専用パネル(ImagePanel)のクラス定義
//
class ImagePanel extends Panel {
  Image img, newimg;  // 元画像 img、新画像 newimgの宣言
  // 拡大縮小のモードviewmode(0:原画像,1:拡大画像)
  // 反転処理のモードflipmode(0:原画像,1:左右反転,2:上下反転,3:90度回転,4:180度回転)
  int viewmode=0, flipmode=0;
  int wpg, hpg; // 画像の幅 wpg、画像の高さ hpg の宣言

  // ImagePanelのコンストラクタ
  ImagePanel(Image img) {  //
    super();         // スーパクラスのコンストラクタの実行
    this.img = img;  // imgの初期化
    newimg = img;    // newimgの初期化
  }

  // 拡大縮小モード設定メソッド
  public void setViewMode(int n) {
    viewmode = n; 
  }

  // 反転処理モード設定メソッド
  public void setFlipMode(int n) {
    flipmode = n; 
  }

  public void setSize(int w, int h) {
    super.setSize( w, h );
  }

  public void flipImage() {
    // まず、画像クラスオブジェクトimg から、画素単位で加工可能な画素配列データへ変換
    PixelGrabber pg = new PixelGrabber(img, 0, 0, -1, -1, true); 
    try {
      if (pg.grabPixels()) {  // 画像取り込み終了の確認
        wpg= pg.getWidth();   // 取り込み画像幅の取得
        hpg= pg.getHeight();  // 取り込み画像高の取得
        int[] pixels=(int[])pg.getPixels(); // 画像の画素配列データの取得
        int[] newpixels=new int[wpg*hpg];   // 新規画素配列データの宣言
        int new_wpg = wpg, new_hpg= hpg;    // 新規画像の幅 new_wpg、高さ new_hpg

        switch (flipmode) {  // 画像反転モードによって、処理内容を選択する。
          case 0: // Original
            for(int y=0; y<hpg ; y++) 
              for(int x=0;x<wpg;x++) newpixels[x+y*wpg]=pixels[x+y*wpg];
            new_wpg = wpg; new_hpg = hpg;
            break;
          case 1: // Flip Horizontal 左右反転
            for(int y=0; y<hpg ; y++) 
              for(int x=0;x<wpg;x++) newpixels[???]=pixels[???];
            new_wpg = ???; new_hpg = ???;
            break;
          case 2: // Flip Vertical 上下反転
            for(int y=0; y<hpg ; y++) 
              for(int x=0;x<wpg;x++) newpixels[???]=pixels[???];
            new_wpg = ???; new_hpg = ???;
            break;
          // 以下、同様に、90度回転、180度回転の場合の処理を追加する。
        }
        // 画像処理結果からImageクラスオブジェクトnewimgを生成する。
        newimg=createImage(new MemoryImageSource(new_wpg,new_hpg,newpixels,0,new_wpg));
      }
    } catch(InterruptedException ie){}
    repaint();
  }

  public void paint(Graphics g) {
    if(newimg!=null){
      if ( viewmode == 0 ) {  // 元画像のサイズで表示
        // 画像newimgをパネルの上部中央に描画
        g.drawImage(newimg, (int)(getSize().width-newimg.getWidth(this))/2, 5, this); 
      } else if ( viewmode == 1 ) {  // ２倍のサイズで表示
        // 画像newimgをパネルの上部中央に描画
        g.drawImage(newimg, (int)(getSize().width-newimg.getWidth(this)*2)/2, 5, 
                     newimg.getWidth(this)*2, newimg.getHeight(this)*2, this);
      }
    }
  }
}

