package ash.util;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Transparency;
import java.awt.RenderingHints;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import static java.awt.image.BufferedImage.TYPE_INT_RGB;
import static java.awt.image.BufferedImage.TYPE_INT_ARGB;

public class ImageUtil {
	/**
	 * 画像の拡大／縮小（高品質モード）
	 * @param pict 画像データ
	 * @param width スケール後の幅
	 * @param height スケール後の高さ
	 */
	public static BufferedImage getScaledImage(BufferedImage pict,
											  int width, int height) {
		return getScaledImage(pict, width, height, true);
	}
	/**
	 * 画像の拡大／縮小
	 * @param pict 画像データ
	 * @param width スケール後の幅
	 * @param height スケール後の高さ
	 * @param quality 1/2以下の縮小での画像品質を優先する。
	 */
	public static BufferedImage getScaledImage(BufferedImage pict,
											  int width, int height,
											  boolean quality) {
		boolean isTranslucent = (pict.getTransparency()!=Transparency.OPAQUE); 
		int type = isTranslucent ? TYPE_INT_ARGB : TYPE_INT_RGB;
		BufferedImage buf = null;
		Graphics2D g2 = null;

		if(quality) {
			// 1/2以下の縮小での品質が良い。性能劣化は中程度。
			int w0 = pict.getWidth();
			int h0 = pict.getHeight();
			int w = w0;
			int h = h0;
			do {
				int prevW = w;
				int prevH = h;
				if(w > width)  w = Math.max(w/2, width);
				if(h > height) h = Math.max(h/2, height);
				if(buf == null || isTranslucent) {
					buf = new BufferedImage(w, h, type);
					if(g2 != null) g2.dispose();
					g2 = buf.createGraphics();
				}
				g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
									RenderingHints.VALUE_INTERPOLATION_BILINEAR);
				// RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
				// RenderingHints.VALUE_INTERPOLATION_BILINEAR,
				// RenderingHints.VALUE_INTERPOLATION_BICUBIC
				g2.drawImage(pict, 0, 0, w, h, 0, 0, prevW, prevH, null);
				pict = buf;
			} while(w != width || h != height);

			g2.dispose();
			if(width == w0 && height == h0) {
				buf = pict;
			} else {
				buf = new BufferedImage(width, height, type);
				g2 = buf.createGraphics();
				g2.drawImage(pict, 0, 0, null);
				g2.dispose();
			}
		} else {
			// この方法は高速であるが、1/2以下の縮小では品質が悪い。
			buf = new BufferedImage(width, height, type);
			g2 = buf.createGraphics();
			g2.drawImage(pict, 0, 0, width, height, null);
			g2.dispose();
		}
		return buf;
	}
	/**
	 * 特定の矩形領域を切り出し、特定のフレームサイズに収まるように縮小する。
	 * @param pict 画像データ
	 * @param b 切り出す矩形領域
	 * @param maxW フレームの幅
	 * @param maxH フレームの高さ
	 * @param quality 1/2以下の縮小での画像品質を優先する。
	 */
	public static BufferedImage getFramedImage(BufferedImage pict, Rectangle b,
											   int maxW, int maxH,
											   boolean quality) {
		if(b.width > maxW || b.height > maxH) {
			int width, height;
			if(b.width * maxH < b.height * maxW) {
				width = b.width * maxH / b.height;
				height = maxH;
			} else {
				height = b.height * maxW / b.width;
				width = maxW;
			}
			BufferedImage image = pict.getSubimage(b.x, b.y, b.width, b.height);
			return getScaledImage(image, width, height, quality);
		} else {
			return pict.getSubimage(b.x, b.y, b.width, b.height);
		}
	}

	private static float[] blurKernel = {
		0.10f, 0.10f, 0.10f,
		0.10f, 0.20f, 0.10f,
		0.10f, 0.10f, 0.10f
	};
	private static ConvolveOp cop = new ConvolveOp(new Kernel(3, 3, blurKernel));
	/**
	 * 特定の矩形領域にぼかしを入れる。
	 * @param pict 画像データ
	 * @param b ぼかしを入れる矩形領域
	 */
	public static void blurFaceImage(BufferedImage pict, Rectangle b) {
		if(b == null) return;
		BufferedImage img = pict.getSubimage(b.x, b.y, b.width, b.height);
        BufferedImage buf = new BufferedImage(b.width, b.height, img.getType());
		cop.filter(img, buf);
		Graphics g = pict.getGraphics();
		g.drawImage(buf.getSubimage(1, 1, b.width - 2, b.height - 2),
					b.x + 1, b.y + 1, null);
		g.dispose();
	}
}
