java生成圖片驗證碼

 

package com.pifeng.util;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

import javax.imageio.ImageIO;

/**
 * @fun 產生圖片驗證碼的工具類
 * @date 2016/8/12
 * @author 皮鋒
 *
 */
public class CaptchaUtil {

	/**
	 * 隨機字典字符,不包括0、O、1、I這些難以辨認的字符
	 */
	private static final char[] CHARS = { '2', '3', '4', '5', '6', '7', '8',
			'9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
			'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };

	/**
	 * 隨機數
	 */
	private static Random random = new Random();

	/**
	 * @fun 獲得length位隨機數
	 * @date 2016/8/12
	 * @author 皮鋒
	 * @param length
	 */
	private static String getRandomString(int length) {
		StringBuffer buffer = new StringBuffer();// 字符串緩存
		for (int i = 0; i < length; i++) {// 循環length次
			// random.nextInt(n)方法調用返回介於0(含)和n(不含)僞隨機,均勻分佈的int值
			buffer.append(CHARS[random.nextInt(CHARS.length)]);// 每次獲取一個隨機字符
		}
		return buffer.toString();
	}

	/**
	 * @fun 獲得隨機的顏色
	 * @date 2016/8/12
	 * @author 皮鋒
	 */
	private static Color getRandomColor() {
		return new Color(random.nextInt(255), random.nextInt(255),random.nextInt(255));
	}

	/**
	 * @fun 獲得某的顏色反色
	 * @date 2016/8/12
	 * @author 皮鋒
	 * @param c
	 */
	private static Color getReverseColor(Color c) {
		return new Color(255 - c.getRed(), 255 - c.getGreen(),255 - c.getBlue());
	}

	/**
	 * @fun 創建驗證碼圖片
	 * @date 2016/8/12
	 * @author 皮鋒
	 * @param width
	 * @param height
	 * @param os
	 * @param randomString
	 * @throws IOException
	 */
	public static void outputImage(int width, int height, OutputStream os,String randomString) throws IOException {
		int verifySize = randomString.length(); // 驗證碼長度
		Color color = getRandomColor();// 隨機顏色,用於背景色
		Color reverse = getReverseColor(color);// 反色,用於前景色

		BufferedImage bi = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);// 創建一個彩色圖片

		Graphics2D g = bi.createGraphics();// 獲取繪圖對象

		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); // 設置圖像抗鋸齒
		g.setFont(new Font(Font.SANS_SERIF, Font.ITALIC, height - 4));// 設置字體: Serif的意思是,在字的筆劃開始及結束的地方有額外的裝飾,而且筆劃的粗細會因直橫的不同而有不同。相反的,Sans Serif則沒有這些額外的裝飾,筆劃粗細大致差不多
		g.setColor(color);// 設置顏色
		g.fillRect(0, 0, width, height);// 繪製背景:用這個顏色填充這個區域
		g.setColor(reverse);// 設置顏色

		for (int i = 0; i < verifySize; i++) { // 繪製驗證碼
			g.drawChars(randomString.toCharArray(), i, 1,((width - 10) / verifySize) * i + 5, height / 2 + height/ 2 - 10);
		}

		drawNoisePoint(width, height, 500, g); // 繪製最多1000個噪音點

		drawInterferingLine(width, height, 30, g); // 產生30條幹擾線

		shear(width, height, g, color);// 使圖片扭曲

		g.dispose();// 釋放由此 Window、其子組件及其擁有的所有子組件所使用的所有本機屏幕資源

		ImageIO.write(bi, "jpg", os);
	}

	/**
	 * @fun 繪製最多num個噪音點
	 * @date 2016/8/12
	 * @author 皮鋒
	 * @param width
	 * @param height
	 * @param num
	 * @param g
	 */
	private static void drawNoisePoint(int width, int height, int num,Graphics2D g) {
		for (int i = 0, n = random.nextInt(num); i < n; i++) {// 繪製最多num個噪音點
			g.drawRect(random.nextInt(width), random.nextInt(height), 1, 1);// 隨機噪音點
		}
	}

	/**
	 * @fun 產生n條幹擾線
	 * @date 2016/8/12
	 * @author 皮鋒
	 * @param width
	 * @param height
	 * @param n
	 * @param g
	 */
	private static void drawInterferingLine(int width, int height, int n,Graphics2D g) {
		for (int i = 0; i < n; i++) {
			int x = random.nextInt(width - 1);
			int y = random.nextInt(height - 1);
			int xl = random.nextInt(6) + 1;
			int yl = random.nextInt(12) + 1;
			g.drawLine(x, y, x + xl + 40, y + yl + 20);
		}
	}

	/**
	 * @fun 使圖片扭曲
	 * @date 2016/8/12
	 * @author 皮鋒
	 * @param width
	 * @param height
	 * @param g
	 * @param color
	 */
	private static void shear(int width, int height, Graphics2D g, Color color) {
		shearX(g, width, height, color);
		shearY(g, width, height, color);
	}

	/**
	 * @fun 使圖片Y軸方向扭曲
	 * @date 2016/8/12
	 * @author 皮鋒
	 * @param g
	 * @param width
	 * @param height
	 * @param color
	 */
	private static void shearY(Graphics2D g, int width, int height, Color color) {
		int period = random.nextInt(40) + 10; // 週期
		int frames = 20; // 幀
		int phase = 7; // 相位
		for (int i = 0; i < width; i++) {
			double d = (double) (period >> 1)* Math.sin((double) i / (double) period + (Math.PI * 2 * (double) phase) / (double) frames);
			g.copyArea(i, 0, 1, height, 0, (int) d);
			g.setColor(color);
			g.drawLine(i, (int) d, i, 0);
			g.drawLine(i, (int) d + height, i, height);
		}
	}

	/**
	 * @fun 使圖片X軸方向扭曲
	 * @date 2016/8/12
	 * @author 皮鋒
	 * @param g
	 * @param width
	 * @param height
	 * @param color
	 */
	private static void shearX(Graphics2D g, int width, int height, Color color) {
		int period = random.nextInt(2);
		int frames = 1;
		int phase = random.nextInt(2);
		for (int i = 0; i < height; i++) {
			double d = (double) (period >> 1)* Math.sin((double) i / (double) period + (Math.PI * 2 * (double) phase) / (double) frames);
			g.copyArea(0, i, width, 1, (int) d, 0);
			g.setColor(color);
			g.drawLine((int) d, i, 0, i);
			g.drawLine((int) d + width, i, width, i);
		}
	}

	/**
	 * @fun 生成指定驗證碼圖像文件
	 * @date 2016/8/12
	 * @author 皮鋒
	 * @param width
	 * @param height
	 * @param file
	 * @param code
	 * @throws IOException
	 */
	public static void outputImageFile(int width, int height, File file,String code) throws IOException {
		if (file == null) {
			return;
		}
		File dir = file.getParentFile();// 獲得父目錄
		if (!dir.exists()) { // 如果父目錄不存在,則創建一個
			dir.mkdirs();
		}
		try {
			file.createNewFile();
			FileOutputStream fos = new FileOutputStream(file);
			outputImage(width, height, fos, code); // 創建驗證碼圖片
			fos.close(); // 關閉流
		} catch (IOException e) {
			throw e;
		}
	}

	public static void main(String[] args) throws IOException {
		File dir = new File("F:/verifies");
		int width = 200, height = 80;
		for (int i = 0; i < 50; i++) {
			String verifyCode = getRandomString(4);
			File file = new File(dir, verifyCode + ".jpg");
			outputImageFile(width, height, file, verifyCode);
		}
	}
}

運行結果:

 

發佈了57 篇原創文章 · 獲贊 43 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章