Java 生成滑动图片验证码, 阴影, 切块
1,效果2,切图工具importjavax.imageio.ImageIO;importjavax.imageio.ImageReadParam;importjavax.image
1, 效果
2, 切图工具
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;
public class ImageUtil {
public static void cut(int x,int y,int width,int height,String srcpath,String subpath) throws IOException {//裁剪方法
FileInputStream is=null;
ImageInputStream iis=null;
try{
is=new FileInputStream(srcpath); //读取原始图片
Iterator<ImageReader>it=ImageIO.getImageReadersByFormatName("jpg"); //ImageReader声称能够解码指定格式
ImageReader reader=it.next();
iis=ImageIO.createImageInputStream(is); //获取图片流
reader.setInput(iis, true); //将iis标记为true(只向前搜索)意味着包含在输入源中的图像将只按顺序读取
ImageReadParam param=reader.getDefaultReadParam(); //指定如何在输入时从 Java Image I/O框架的上下文中的流转换一幅图像或一组图像
Rectangle rect=new Rectangle(x, y, width, height); //定义空间中的一个区域
param.setSourceRegion(rect); //提供一个 BufferedImage,将其用作解码像素数据的目标。
BufferedImage bi=reader.read(0, param); //读取索引imageIndex指定的对象
ImageIO.write(bi, "jpg", new File(subpath)); //保存新图片
}finally{
if(is!= null)
is.close();
if(iis != null)
iis.close();
}
}
public void cutByTemplate2(BufferedImage oriImage,BufferedImage newSrc,BufferedImage newSrc2,int x,int y,int width,int height, int c_a, int c2_b){
//固定圆半径为5
int c_r=10;
double rr=Math.pow(c_r, 2);//r平方
//圆心的位置 cb
//System.out.println(c_a);
int c_b=y;
//第二个圆(排除圆内的点) c2_a
int c2_a=x;
//System.out.println(oriImage.getWidth()+" "+oriImage.getHeight());
for(int i=0;i<oriImage.getWidth();i++){
for(int j=0;j<oriImage.getHeight();j++){
//data[i][j]=oriImage.getRGB(i,j);
//(x-a)²+(y-b)²=r²中,有三个参数a、b、r,即圆心坐标为(a,b),半径r。
double f=Math.pow((i-c_a), 2)+Math.pow((j-c_b), 2);
double f2=Math.pow((i-c2_a), 2)+Math.pow((j-c2_b), 2);
int rgb=oriImage.getRGB(i,j);
if(i>=x&&i<(x+width) &&j>=y&&j<(y+height) && f2>=rr){//在矩形内
//块范围内的值
in(newSrc, newSrc2, i, j, rgb);
}else if(f<=rr){
//在圆内
in(newSrc, newSrc2, i, j, rgb);
}else{
//剩余位置设置成透明
out(newSrc, newSrc2, i, j, rgb);
}
}
}
}
private void in(BufferedImage newSrc,BufferedImage newSrc2,int i,int j,int rgb){
newSrc.setRGB(i, j, rgb);
//原图设置变灰
int r = (0xff & rgb);
int g = (0xff & (rgb >> 8));
int b = (0xff & (rgb >> 16));
rgb = r + (g << 8) + (b << 16) + (100 << 24);
//rgb = r + (g << 8) + (b << 16);
newSrc2.setRGB(i, j, rgb);
newSrc.setRGB(i + 1, j + 1, rgb);
}
private void out(BufferedImage newSrc,BufferedImage newSrc2,int i,int j,int rgb){
newSrc.setRGB(i, j, 0x00ffffff);
newSrc2.setRGB(i, j, rgb);
}
public static BufferedImage createDropShadow(BufferedImage image,
int size, float opacity) {
int width = image.getWidth() + size * 2;
int height = image.getHeight() + size * 2;
BufferedImage mask = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = mask.createGraphics();
g2.drawImage(image, size, size, null);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN,
opacity));
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, width, height);
g2.dispose();
BufferedImage shadow = createBlurOp(size).filter(mask, null);
g2 = shadow.createGraphics();
g2.dispose();
return shadow;
}
private static ConvolveOp createBlurOp(int size) {
float[] data = new float[size * size];
float value = 1f / (float) (size * size);
for (int i = 0; i < data.length; i++) {
data[i] = value;
}
return new ConvolveOp(new Kernel(size, size, data),
ConvolveOp.EDGE_NO_OP, null);
}
}
3, 生成背景图
x就是验证码, x 轴的偏移量, 验证就是需要这个
@GetMapping("/xcode")
public Result getXCode1(HttpServletResponse resp, HttpServletRequest request) throws IOException {
ImageUtil tt = new ImageUtil();
// 随机选择背景图
int num = new Random().nextInt(10) + 1;
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("xcode/" + num + ".jpg");
BufferedImage src= ImageIO.read(resourceAsStream);
//移动图
BufferedImage newSrc=new BufferedImage(src.getWidth(), src.getHeight(),BufferedImage.TYPE_4BYTE_ABGR);//新建一个类型支持透明的BufferedImage
//对比图
BufferedImage newSrc2=new BufferedImage(src.getWidth(), src.getHeight(),BufferedImage.TYPE_4BYTE_ABGR);//新建一个类型支持透明的BufferedImage
//抠块的大小
int blockWidth=48;
int blockHeight=48;
// 用于生成 移动图
XCodeTdo code = new XCodeTdo();
code.setNum(num);
Random rand1=new Random();
int x=rand1.nextInt(src.getWidth()-blockWidth-20)+20;//10,width-200
if (x > 210 - 58) {
x = 210 - 58;
}
Random rand2=new Random();
int y=rand2.nextInt(src.getHeight()-blockHeight-20)+20;//
code.setX(x);
code.setY(y);
int ca = new Random().nextInt(blockWidth-2*20)+(x+20);
int cb = new Random().nextInt(blockHeight-2*20)+(y+20);
code.setCa(ca);
code.setCb(cb);
tt.cutByTemplate2(src,newSrc,newSrc2,x,y,blockWidth,blockHeight, ca, cb);//图片大小是固定,位置是随机
request.getSession().setAttribute("X_CODE", JSON.toJSONString(code));
//生成对比图
ImageIO.write(newSrc2, "png", resp.getOutputStream());
return null;
}
4, 生成区块图
@GetMapping("/xcodem")
public Result getXCode2(HttpServletResponse resp, HttpServletRequest request) throws IOException {
ImageUtil tt = new ImageUtil();
Object o = request.getSession().getAttribute("X_CODE");
if (o == null) {
return new Result();
}
XCodeTdo codeTdo = JSON.parseObject(String.valueOf(o), XCodeTdo.class);
int num = codeTdo.getNum();
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("xcode/" + num + ".jpg");
BufferedImage src= ImageIO.read(resourceAsStream);
//移动图
BufferedImage newSrc=new BufferedImage(src.getWidth(), src.getHeight(),BufferedImage.TYPE_4BYTE_ABGR);//新建一个类型支持透明的BufferedImage
//对比图
BufferedImage newSrc2=new BufferedImage(src.getWidth(), src.getHeight(),BufferedImage.TYPE_4BYTE_ABGR);//新建一个类型支持透明的BufferedImage
//抠块的大小
int x= codeTdo.getX();
int y= codeTdo.getY();
tt.cutByTemplate2(src,newSrc,newSrc2,x,y,48,48, codeTdo.getCa(), codeTdo.getCb());//图片大小是固定,位置是随机
newSrc = newSrc.getSubimage(x - 1, 0, 58, 210);
//ImageUtil.createDropShadow(newSrc, 3, 0.08f);
//生成对比图
ImageIO.write(newSrc, "png", resp.getOutputStream());
return null;
}
5, 阴影图
@GetMapping("/xcodey")
public void getXCode3(HttpServletResponse resp, HttpServletRequest request) throws IOException {
ImageUtil tt = new ImageUtil();
Object o = request.getSession().getAttribute("X_CODE");
if (o == null) {
return;
}
XCodeTdo codeTdo = JSON.parseObject(String.valueOf(o), XCodeTdo.class);
int num = codeTdo.getNum();
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("xcode/" + num + ".jpg");
BufferedImage src= ImageIO.read(resourceAsStream);
//移动图
BufferedImage newSrc=new BufferedImage(src.getWidth(), src.getHeight(),BufferedImage.TYPE_4BYTE_ABGR);//新建一个类型支持透明的BufferedImage
//对比图
BufferedImage newSrc2=new BufferedImage(src.getWidth(), src.getHeight(),BufferedImage.TYPE_4BYTE_ABGR);//新建一个类型支持透明的BufferedImage
//抠块的大小
int x= codeTdo.getX();
int y= codeTdo.getY();
tt.cutByTemplate2(src,newSrc,newSrc2,x,y,48,48, codeTdo.getCa(), codeTdo.getCb());//图片大小是固定,位置是随机
newSrc = newSrc.getSubimage(x - 1, 0, 48, 210);
newSrc = ImageUtil.createDropShadow(newSrc, 4, 0.6f);
//生成对比图
ImageIO.write(newSrc, "png", resp.getOutputStream());
}
public class XCodeTdo {
private int num;
private int x;
private int y;
private int ca;
private int cb;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getCa() {
return ca;
}
public void setCa(int ca) {
this.ca = ca;
}
public int getCb() {
return cb;
}
public void setCb(int cb) {
this.cb = cb;
}
}
4, 怎么验证?
前端需要传 x 轴的偏移量, 与第一次生成的背景图保存在session 中的 X_CODE, 中的x进行比较值
@RequestMapping(value = "/login", method = RequestMethod.POST)
@ResponseBody
public Object loginVali(HttpServletRequest request) {
String username = super.getPara("username").trim();
String password = super.getPara("password").trim();
String xcode= super.getPara("xcode");
int token = Integer.parseInt(xcode);
Object obj = request.getSession().getAttribute("X_CODE");
XCodeTdo codeTdo = JSON.parseObject(String.valueOf(obj), XCodeTdo.class);
// 这里 / 2.1 是因为前端的滑动器值是100
int x = (int) (codeTdo.getX() / 2.1);
// 预留了正负6 * 2.1 = 13的像素的偏差
if (token > x + 3 || token < x - 3) {
// 删除验证记录
request.getSession().removeAttribute("X_CODE");
return new SuccessTip(400,"验证码错误!",null);
}
return new SuccessTip(200,"登录成功!",null);
}
相关文章
发表评论
评论列表
- 这篇文章还没有收到评论,赶紧来抢沙发吧~