package prog;

/*  2006/12/26
 *  c0104401 吉原美樹
 *  土曜prog img_make.java
 *  写真（jpg）を読み込みサンプルを作成しpngファイルに出力する
 *  
 *  Ver.0.5 int型の引数で呼び出されるように修正
 *  Ver.0.8 "次へ"を設置（押すとhair_sample.pngを上書き保存）
 *  Ver.1.0 "次へ"ボタンを破棄（画像の保存は変数で制御し
 *  一番最初とカラーパレットから色を選ぶ度に行う
 *  毎回jpgを読み込んでいたものを
 *  起動時に一度だけ読み込むように変更
 *  それに伴いアルファ値のセット・リセットを記述
 *  コメントを追加
 *  範囲選択の部分を修正
 *  ドラッグ中に写真外に出た場合は写真のへりに点を取ったことにする
 *  変数の出力ファイル名（output_name）以外をprivate化 */

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;

class img_make extends JFrame{
	/**
	 *
	 */

	// シリアル番号
	private static final long serialVersionUID = 1L;

	// ----------------- 変数の宣言↓ここから↓ -----------------

	// 顧客番号
	private String name_id = "0000000000000"; 	// 初期値は0000000000000
	private int nameid_num = 12 ; 				// 何桁か

	// 出力するファイル名（外部から操作可能）
	String output_name = "hair_sample.png" ;

	// 表示
	private Graphics2D g_base;

	// ベース（全体を一枚の絵にしてから表示する）
	private Graphics2D base_draw;
	private BufferedImage baseImage = null;

	// 写真の部分(ファイルに出力する）
	private Graphics2D pict_draw;
	private BufferedImage hairImage = null;
	private BufferedImage hairImage_buf = null;
	
	// 画面のサイズ
	private static int win_width = 750 ; 		// 横
	private static int win_height = 440 ; 		// 縦

	// トリミングや空白の数値
	private int pict_left = 20 ; 		// 写真左部の空白
	private int pict_top = 20 ; 		// 写真上部の空白
	private int pict_width = 260 ; 		// 写真の横
	private int pict_height = 400 ; 	// 写真の縦

	private int colorbox_size = 100 ;	// カラーパレットのひとつの升目の縦と横（正方形）
	private int colorbox_gap = 5; 		// カラーパレット同士の間の空白

	// カラーパレット1左部↓
	private int colorbox1_left = pict_left + pict_width + 40 ;
	// カラーパレット2左部↓
	private int colorbox2_left = colorbox1_left + colorbox_size + colorbox_gap ;
	// カラーパレット3左部↓
	private int colorbox3_left = colorbox2_left + colorbox_size + colorbox_gap ;
	// カラーパレット4左部↓
	private int colorbox4_left = colorbox3_left + colorbox_size + colorbox_gap ;

	//カラーパレット1~4上部↓
	private int colorbox1_top = pict_top + 60 ;

	// カラーパレット5左部↓
	private int colorbox5_left = colorbox1_left ;
	// カラーパレット6左部↓
	private int colorbox6_left = colorbox5_left + colorbox_size + colorbox_gap ;
	// カラーパレット7左部↓
	private int colorbox7_left = colorbox6_left + colorbox_size + colorbox_gap ;
	// カラーパレット8左部↓
	private int colorbox8_left = colorbox7_left + colorbox_size + colorbox_gap ;

	// カラーパレット5~8上部↓
	private int colorbox5_top = colorbox1_top + colorbox_size + colorbox_gap ;

	// マウスの座標を読み込むための変数
	private double mouseX = 0 ; 		// x座標
	private double mouseY = 0 ; 		// y座標

	// カラーリング指定の色宣言
	private String what_color = "0x000000"; // これで指定（初期値は黒）
	// 上の段の四色
	private String color_1 = "0xFF0000"; // 赤
	private String color_2 = "0x000000"; // 黒
	private String color_3 = "0xFFFF00"; // 黄
	private String color_4 = "0x0000FF"; // 青

	// 下の段の四色
	private String color_5 = "0x999999"; // 灰
	private String color_6 = "0x009933"; // 緑
	private String color_7 = "0x663300"; // 茶
	private String color_8 = "0xFFCCCC"; // ピンク

	// 髪色の範囲が選択されているか否か
	private int hair_scope_num = 0 ; 		// 選択された点はいくつあるか（2未満では未選択と判定）
	private int hair_pointMax = 10000 ; 	// 点をいくつ使うか
	private int hairX[] = new int[hair_pointMax]; // 選択された点のx座標
	private int hairY[] = new int[hair_pointMax]; // 選択された点のy座標

	// 髪色の範囲を選択している最中か否か
	//（マウスのボタンが写真中で行われた場合にtrue、マウスのボタンが離されるとfalse）
	private boolean hair_scoping = false ; 	// 初期値は"選択中ではない"
	private boolean read_pict = true ; 		// 写真を背景に読み込むか

	private double point_beginX; 	// 選択線の始点x座標
	private double point_beginY; 	// 選択線の始点y座標
	private double point_endX; 		// 選択線の終点x座標
	private double point_endY; 		// 選択線の終点y座標

	// 領域選択に使う変数
	private int line_count = 0;
	private int line_every = 3; // 何回呼び出される毎にポイントを取得するか

	// カラーパレットのボタンが押されたかどうか
	private boolean hair_coloring = false ;

	// 画像を保存するかどうか
	private boolean pict_out = false ;
	
	// 透過度を指定
	private float alpha = 0.3f; // between 0.0f and 1.0f
	// セット
	private AlphaComposite alphaComposite_set = AlphaComposite.getInstance( AlphaComposite.SRC_OVER, alpha );
	// リセット（不透明に戻す）
	private AlphaComposite alphaComposite_reset = AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 1.0f );
	
	// ----------------- 変数の宣言↑ここまで↑ -----------------

	public img_make(int id) {
		int i,j, ex_num = 0 ; 	// int変数を文字列に変換するための準備1
		String ex_str ; 		// int変数を文字列に変換するための準備2
		ex_str = Integer.toString (id); // 顧客番号をint型からString型に変換

		// ファイル名の桁数（nameid_num）に足りない分の桁数を数える
		if(id == 0){ // id番号が0のときは別処理
			ex_num = nameid_num ;
		}
		else{// id番号が0より大きい場合
			j = id ;
			for(i=0;j>0;i++){
				j = j/10 ;
				ex_num = nameid_num - i;
			}
		}//else

		name_id = ""; // name_idを空にする
		for(i=0;i<ex_num-1;i++){ // 足りない分だけ頭に0を詰める
			name_id = name_id + "0";
		}

		name_id = name_id + ex_str; // 受け取ったid番号を後ろにつける

	    // マウスがドラッグをしているときの動きを監視
		addMouseMotionListener(new MouseMotionAdapter() {
			public void mouseDragged(MouseEvent e) {
				// 髪色の範囲を選択中のときのみ実行する
				if(hair_scoping){
		    		mouseX = e.getX(); // x座標
		    		mouseY = e.getY(); // y座標
		    		if(mouseX < pict_left + 1){// x座標が範囲より左にあった
		    			mouseX = pict_left + 1 ; // x座標を左縁にとる
		    		}
		    		else if(mouseX > pict_left + pict_width - 1){// x座標が範囲より右にあった
		    			mouseX = pict_left + pict_width - 1 ;// x座標を右縁にとる
		    		}
		    		if(mouseY < pict_top + 1){// y座標が範囲より上にあった
		    			mouseY = pict_top + 1 ;// y座標を上縁にとる
		    		}
		    		else if(mouseY > pict_top + pict_height - 1){// x座標が範囲より下にあった
		    			mouseY = pict_top + pict_height - 1 ;// y座標を下縁にとる
		    		}
		    		
					line_count++; // 範囲の選択中にこの命令が何度呼び出されたかを加算
					if(line_count%line_every == 0){// 何度か呼び出されるごとに点をとる
						point_beginX = point_endX; // 始点のx座標（前回の終点のx座標）
						point_beginY = point_endY; // 始点のy座標（前回の終点のy座標）
						point_endX = mouseX - pict_left; // 終点のx座標
						point_endY = mouseY - pict_top; // 終点のy座標

						hairX[hair_scope_num] = (int)point_endX; // 選択点のx座標
						hairY[hair_scope_num] = (int)point_endY; // 選択点のy座標
						hair_scope_num++; // 次の選択点へ

						// 点が移動していた場合だけ線を描く
						// (始点のx座標と終点のx座標が一致しない
						// または、始点のy座標と終点のy座標が一致しない）
						if((point_beginX != point_endX)||(point_beginY != point_endY)){
							repaint(); // 描画関数を呼び出す
						}
					}//if(line...
				}//if(hair...
			}
		});
		addMouseListener(new MouseAdapter() {

	    	// マウスのボタン（左）が押された
	    	public void mousePressed(MouseEvent e){
	    		mouseX = e.getX(); // x座標
	    		mouseY = e.getY(); // y座標

	    		// --- 写真の中だった場合↓ここから↓ ---
	    		if((mouseX > pict_left && mouseX < pict_left + pict_width)
	    				&&(mouseY > pict_top && mouseY < pict_top + pict_height)){

	    			// hair_scopingをtrueにすることで
	    			// 髪色の範囲を選択中であることを示す
	    			hair_scoping = true ;

	    			// 初期化
	    			hair_scope_num = 0;		// 選択点を0に
					read_pict = true ; 		// 写真を読み込む
	    			hair_coloring = false ;	// カラーパレット未選択

	    			point_beginX = point_endX = mouseX - pict_left; // 始点x座標＝終点x座標
					point_beginY = point_endY = mouseY - pict_top; 	// 始点y座標＝終点y座標

					hairX[hair_scope_num] = (int)point_endX ;	// 選択点のx座標 
					hairY[hair_scope_num] = (int)point_endY ; 	// 選択点のy座標
					hair_scope_num++; // 次の選択点へ
	    		}
	    		// --- 写真の中だった場合↑ここまで↑ ---

	    		// --- カラーパレットの上部中だった場合↓ここから↓ ---
	    		else if(mouseY > colorbox1_top && mouseY < colorbox1_top + colorbox_size){
		    		// カラーパレットの1の中だった場合
		    		if(mouseX > colorbox1_left && mouseX < colorbox1_left + colorbox_size){
		    			what_color = color_1 ;
						read_pict = true ; 		// 写真を読み込む
		    			hair_coloring = true ; 	// カラーパレットが選択された
						repaint();
		    		}
		    		// カラーパレットの2の中だった場合
		    		else if(mouseX > colorbox2_left && mouseX < colorbox2_left + colorbox_size){
		    			what_color = color_2 ;
		    			read_pict = true ; 		// 写真を読み込む
		    			hair_coloring = true ; 	// カラーパレットが選択された
						repaint();
		    		}
		    		// カラーパレットの3の中だった場合
		    		else if(mouseX > colorbox3_left && mouseX < colorbox3_left + colorbox_size){
		    			what_color = color_3 ;
		    			read_pict = true ; 		// 写真を読み込む
		    			hair_coloring = true ; 	// カラーパレットが選択された
						repaint();
		    		}
		    		// カラーパレットの4の中だった場合
		    		else if(mouseX > colorbox4_left && mouseX < colorbox4_left + colorbox_size){
		    			what_color = color_4 ;
		    			read_pict = true ; 		// 写真を読み込む
		    			hair_coloring = true ; 	// カラーパレットが選択された
						repaint();
		    		}
	    		}
	    		// --- カラーパレットの上部中だった場合↑ここまで↑ ---

	    		// --- カラーパレットの下部中だった場合↓ここから↓ ---
	    		else if(mouseY > colorbox5_top && mouseY < colorbox5_top + colorbox_size){
		    		// カラーパレットの5の中だった場合
		    		if(mouseX > colorbox5_left && mouseX < colorbox5_left + colorbox_size){
		    			what_color = color_5 ;
		    			read_pict = true ; 		// 写真を読み込む
		    			hair_coloring = true ; 	// カラーパレットが選択された
						repaint();

		    		}
		    		// カラーパレットの6の中だった場合
		    		else if(mouseX > colorbox6_left && mouseX < colorbox6_left + colorbox_size){
		    			what_color = color_6 ;
		    			read_pict = true ; 		// 写真を読み込む
		    			hair_coloring = true ; 	// カラーパレットが選択された
						repaint();
		    		}
		    		// カラーパレットの7の中だった場合
		    		else if(mouseX > colorbox7_left && mouseX < colorbox7_left + colorbox_size){
		    			what_color = color_7 ;
		    			read_pict = true ; 		// 写真を読み込む
		    			hair_coloring = true ; 	// カラーパレットが選択された
						repaint();
		    		}
		    		// カラーパレットの8の中だった場合
		    		else if(mouseX > colorbox8_left && mouseX < colorbox8_left + colorbox_size){
		    			what_color = color_8 ;
		    			read_pict = true ; 		// 写真を読み込む
		    			hair_coloring = true ; 	// カラーパレットが選択された
						repaint();
		    		}
	    		}
	    		// --- カラーパレットの下部中だった場合↑ここまで↑ ---

	    	}//mousePressed()

	    	// マウスのボタン（左）が離された
	    	public void mouseReleased(MouseEvent e){
				// 髪色の範囲を選択中のときのみ実行する
				if(hair_scoping){
					point_beginX = point_endX;
					point_beginY = point_endY;
					point_endX = hairX[0]; // 選択範囲の基点を終点に（x座標）
					point_endY = hairY[0]; // 選択範囲の基点を終点に（y座標）
					repaint();
					hair_scoping = false ; // 初期化（髪の範囲選択を終えた）
				}//if(hair...
	    	}//mouseReleased()

	    });//addMouseListener()
	}
	
	// ---------------- 描画関数↓ここから↓ ----------------------------
	public void paint(Graphics g){
		int i;
		g_base = (Graphics2D)g;
	
		// baseImageは一回だけ作成される
		if(baseImage==null){
	       baseImage = new BufferedImage(getWidth(), getHeight(),
	       		BufferedImage.TYPE_INT_BGR);
	       // baseImageに手を加える宣言
	       base_draw = baseImage.createGraphics();
	       base_draw.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
	       		RenderingHints.VALUE_ANTIALIAS_ON);
	       
	       // 一度だけhairImage_bufに写真を読み込んでおき
	       // 書き換えるときはhairImageの上にhairImage_bufを上書きする
	       try {
	    	   // 写真を読み込む
	    	   hairImage_buf = ImageIO.read(new File("date/"+name_id+".jpg"));
	       } catch (Exception e) {
	    	   //読み込めなかったら黒く塗られる
	    	   e.printStackTrace();
	    	   hairImage_buf = new BufferedImage(pict_width, pict_height,
	           		BufferedImage.TYPE_INT_BGR);
	       }
	       // hairImageの初期化（真っ黒）
    	   hairImage = new BufferedImage(pict_width, pict_height,
	           		BufferedImage.TYPE_INT_BGR);
	       			
	       // hairImageに手を加える宣言
	       pict_draw = hairImage.createGraphics();
	       pict_draw.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);

	       // 画面全体を白く塗りつぶす
	       base_draw.setColor(Color.white);
	       base_draw.fill(new Rectangle2D.Double(0, 0, win_width, win_height));
	
	       // 黒で文字を書く
	       base_draw.setColor(Color.black);
	       base_draw.setFont(new Font("Serif",Font.BOLD,30)); // フォントの設定
	       base_draw.drawString("カラーパレット",colorbox1_left,colorbox1_top-20);
	
	       // カラーパレット1
	       base_draw.setColor(Color.decode(color_1));
	       base_draw.fill(new Rectangle2D.Double(colorbox1_left, colorbox1_top,
	       		colorbox_size, colorbox_size));
	       // カラーパレット2
	       base_draw.setColor(Color.decode(color_2));
	       base_draw.fill(new Rectangle2D.Double(colorbox2_left, colorbox1_top,
	       		colorbox_size, colorbox_size));
	       // カラーパレット3
	       base_draw.setColor(Color.decode(color_3));
	       base_draw.fill(new Rectangle2D.Double(colorbox3_left, colorbox1_top,
	       		colorbox_size, colorbox_size));
	       // カラーパレット4
	       base_draw.setColor(Color.decode(color_4));
	       base_draw.fill(new Rectangle2D.Double(colorbox4_left, colorbox1_top,
	       		colorbox_size, colorbox_size));
	
	       // カラーパレット5
	       base_draw.setColor(Color.decode(color_5));
	       base_draw.fill(new Rectangle2D.Double(colorbox5_left, colorbox5_top,
	       		colorbox_size, colorbox_size));
	       // カラーパレット6
	       base_draw.setColor(Color.decode(color_6));
	       base_draw.fill(new Rectangle2D.Double(colorbox6_left, colorbox5_top,
	       		colorbox_size, colorbox_size));
	       // カラーパレット7
	       base_draw.setColor(Color.decode(color_7));
	       base_draw.fill(new Rectangle2D.Double(colorbox7_left, colorbox5_top,
	       		colorbox_size, colorbox_size));
	       // カラーパレット8
	       base_draw.setColor(Color.decode(color_8));
	       base_draw.fill(new Rectangle2D.Double(colorbox8_left, colorbox5_top,
	       		colorbox_size, colorbox_size));
	       
	       // 一番初めは、画像を保存する
	       pict_out = true ;
		}
	
		// ------------- 写真部分の描画↓ここから↓ ----------------
		if(read_pict){// 最初と再描画する場合
				// hairImageにhairImage_bufを上書き
				pict_draw.drawImage(hairImage_buf, 0, 0, this);
				// 写真の読み込みをしない（選択中は線を書き加えていくだけ）
				read_pict = false ;
		}
	
		// カラーパレットのボタンが押された
		if(hair_coloring){
			pict_draw.setComposite( alphaComposite_set );		// 透過度をセット
			pict_draw.setColor(Color.decode(what_color));		// 選択された色をセット
	
			// 範囲選択済みの場合はポリゴンを作成し塗りつぶす
			if(hair_scope_num>2){
				// 新規オブジェクトの構築（ポリゴン）
				GeneralPath hair_polygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
				
				hair_polygon.moveTo(hairX[0], hairY[0]); 	// 基点を移動
				for(i=1;i<hair_scope_num;i++){ 				// 点の数だけ繰り返す
					// 前の点から現在の点へポリゴン
					hair_polygon.lineTo(hairX[i],hairY[i]);
				}
				hair_polygon.closePath();					// ポリゴンを閉じる
				pict_draw.fill(hair_polygon);				// 塗りつぶす
			}
			// 範囲選択済みでない場合は写真全体を塗りつぶす
			else{
				pict_draw.fill(new Rectangle2D.Double(0, 0, pict_width, pict_height));
			}
			
			// 画像を保存する
			pict_out = true ;
			pict_draw.setComposite( alphaComposite_reset );			// 透過度をリセット
	   }//if(hair...
	
	   // カラーパレットのボタンが押された以外で再描画
	   // （写真中でマウスのボタンが押され、髪色範囲指定の最中）
	   else{
	       BasicStroke wideStroke = new BasicStroke(2.0f);
	       pict_draw.setStroke(wideStroke);
	       pict_draw.setPaint(Color.red);
	       pict_draw.draw(new Line2D.Double(point_beginX,point_beginY,point_endX,point_endY));
	   }//else
		// ------------- 写真部分の描画↑ここまで↑ ----------------
	
	   // 作成した写真（hairImage）をベース（baseImage）に貼り付ける
		base_draw.drawImage(hairImage, pict_top, pict_left, this);
		// ベース（baseImage）を表示する
		g_base.drawImage(baseImage, 0, 0, this);
		
		if(pict_out){// 作成した写真（hairImage）を保存する
			try {
				ImageIO.write(hairImage, "png", new File(output_name));
			} catch (Exception e) {//
				e.printStackTrace();
			}
			// 写真の保存をオフにする
			pict_out = false ;
		}//if
	}
	// ---------------- 描画関数↑ここまで↑ ----------------------------
}