1
0
mirror of https://github.com/whvcse/EasyCaptcha.git synced 2024-11-23 01:59:19 +08:00

修复验证码位数的bug,优化代码

This commit is contained in:
synchronized 2018-07-27 12:02:33 +08:00
parent a4e61fd633
commit a548f7af0b
16 changed files with 675 additions and 461 deletions

43
.gitignore vendored
View File

@ -1,24 +1,25 @@
# Compiled class file /target/
*.class !.mvn/wrapper/maven-wrapper.jar
# Log file ### STS ###
*.log .apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
# BlueJ files ### IntelliJ IDEA ###
*.ctxt .idea
*.iws
*.iml
*.ipr
# Mobile Tools for Java (J2ME) ### NetBeans ###
.mtj.tmp/ /nbproject/private/
/build/
# Package Files # /nbbuild/
*.jar /dist/
*.war /nbdist/
*.ear /.nb-gradle/
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/bin
/target

6
.idea/encodings.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$" charset="UTF-8" />
</component>
</project>

View File

@ -0,0 +1,13 @@
<component name="libraryTable">
<library name="Maven: junit:junit:4.7">
<CLASSES>
<root url="jar://$USER_HOME$/.m2/repository/junit/junit/4.7/junit-4.7.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$USER_HOME$/.m2/repository/junit/junit/4.7/junit-4.7-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$USER_HOME$/.m2/repository/junit/junit/4.7/junit-4.7-sources.jar!/" />
</SOURCES>
</library>
</component>

124
.idea/uiDesigner.xml Normal file
View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

View File

@ -5,10 +5,12 @@
<output-test url="file://$MODULE_DIR$/target/test-classes" /> <output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" /> <excludeFolder url="file://$MODULE_DIR$/target" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="PROVIDED" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.7" level="project" />
</component> </component>
</module> </module>

161
pom.xml
View File

@ -1,30 +1,137 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>EasyCaptcha</groupId>
<artifactId>EasyCaptcha</artifactId>
<version>1.1.0-RELEASE</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>6</source>
<target>6</target>
</configuration>
</plugin>
</plugins>
</build>
<name>EasyCaptcha</name>
<dependencies> <groupId>com.github.whvcse</groupId>
<!-- j2ee环境 -->
<dependency> <artifactId>EasyCaptcha</artifactId>
<groupId>javax.servlet</groupId> <version>1.1.0-RELEASE</version>
<artifactId>javax.servlet-api</artifactId> <packaging>jar</packaging>
<version>3.1.0</version>
<scope>provided</scope> <name>EasyCaptcha</name>
</dependency> <description>Java web图形验证码支持gif验证码。</description>
</dependencies> <url>https://github.com/whvcse/EasyCaptcha</url>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>7</version>
</parent>
<dependencies>
<!-- j2ee环境 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>6</source>
<target>6</target>
</configuration>
</plugin>
</plugins>
</build>
<scm>
<url>https://github.com/whvcse/EasyCaptcha</url>
<connection>scm:git:git@github.com:whvcse/EasyCaptcha</connection>
<developerConnection>scm:git:git@github.com:whvcse/EasyCaptcha</developerConnection>
<tag>HEAD</tag>
</scm>
<developers>
<developer>
<name>whvcse</name>
<email>whvcse@foxmail.com</email>
<url>https://github.com/whvcse</url>
</developer>
</developers>
<distributionManagement>
<snapshotRepository>
<id>oss</id>
<name>OSS Snapshots Repository</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>oss</id>
<name>OSS Staging Repository</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<!-- Source -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project> </project>

View File

@ -5,100 +5,114 @@ import java.awt.Font;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
* <p> * 验证码抽象类
* 验证码抽象类,暂时不支持中文 * Created by 王帆 on 2018-07-27 上午 10:08.
* </p>
*
* @author: wuhongjun
* @version:1.0
*/ */
public abstract class Captcha extends Randoms { public abstract class Captcha extends Randoms {
protected Font font = new Font("Verdana", Font.ITALIC | Font.BOLD, 28); // 字体 protected Font font = new Font("Verdana", Font.ITALIC | Font.BOLD, 28); // 字体
protected int len = 5; // 验证码随机字符长度 protected int len = 5; // 验证码随机字符长度
protected int width = 150; // 验证码显示 protected int width = 150; // 验证码显示
protected int height = 40; // 验证码显示高度 protected int height = 40; // 验证码显示高度
private String chars = null; // 随机字符串 private String chars = null; // 当前验证码
/** /**
* 生成随机字符数组 * 生成随机验证码
* *
* @return 字符数组 * @return 验证码字符数组
*/ */
protected char[] alphas() { protected char[] alphas() {
char[] cs = new char[len]; char[] cs = new char[len];
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
cs[i] = alpha(); cs[i] = alpha();
} }
chars = new String(cs); chars = new String(cs);
return cs; return cs;
} }
public Font getFont() { /**
return font; * 给定范围获得随机颜色
} *
* @param fc 0-255
* @param bc 0-255
* @return 随机颜色
*/
protected Color color(int fc, int bc) {
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + num(bc - fc);
int g = fc + num(bc - fc);
int b = fc + num(bc - fc);
return new Color(r, g, b);
}
public void setFont(Font font) { /**
this.font = font; * 验证码输出,抽象方法由子类实现
} *
* @param os 输出流
* @return 是否成功
*/
public abstract boolean out(OutputStream os);
public int getLen() { /**
return len; * 获取当前的验证码
} *
* @return 字符串
*/
public String text() {
checkAlpha();
return chars;
}
public void setLen(int len) { /**
this.len = len; * 获取当前验证码的字符数组
} *
* @return 字符数组
*/
public char[] textChar() {
checkAlpha();
return chars.toCharArray();
}
public int getWidth() { /**
return width; * 检查验证码是否生成没有这立即生成
} */
public void checkAlpha() {
if (chars == null) {
alphas(); // 生成验证码
}
}
public void setWidth(int width) { public Font getFont() {
this.width = width; return font;
} }
public int getHeight() { public void setFont(Font font) {
return height; this.font = font;
} }
public void setHeight(int height) { public int getLen() {
this.height = height; return len;
} }
/** public void setLen(int len) {
* 给定范围获得随机颜色 this.len = len;
* }
* @return Color 随机颜色
*/
protected Color color(int fc, int bc) {
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + num(bc - fc);
int g = fc + num(bc - fc);
int b = fc + num(bc - fc);
return new Color(r, g, b);
}
/** public int getWidth() {
* 验证码输出,抽象方法由子类实现 return width;
* }
* @param os
* 输出流
*/
public abstract void out(OutputStream os);
/** public void setWidth(int width) {
* 获取随机字符串 this.width = width;
* }
* @return string
*/ public int getHeight() {
public String text() { return height;
return chars; }
}
public void setHeight(int height) {
public char[] textChar() { this.height = height;
return chars.toCharArray(); }
}
} }

View File

@ -4,40 +4,20 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
* @author: wuhongjun *
* @version:1.0
*/ */
public class Encoder public class Encoder {
{
private static final int EOF = -1; private static final int EOF = -1;
// 图片的宽高
private int imgW, imgH; private int imgW, imgH;
private byte[] pixAry; private byte[] pixAry;
private int initCodeSize; private int initCodeSize; // 验证码位数
private int remaining; private int remaining; // 剩余数量
private int curPixel; private int curPixel; // 像素
// GIFCOMPR.C - GIF Image compression routines
//
// Lempel-Ziv compression based on 'compress'. GIF modifications by
// David Rowley (mgardi@watdcsu.waterloo.edu)
// General DEFINEs
static final int BITS = 12; static final int BITS = 12;
static final int HSIZE = 5003; // 80% occupancy static final int HSIZE = 5003; // 80% 占用率
// GIF Image compression - modified 'compress'
//
// Based on: compress.c - File compression ala IEEE Computer, June 1984.
//
// By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
// Jim McKie (decvax!mcvax!jim)
// Steve Davies (decvax!vax135!petsd!peora!srd)
// Ken Turkowski (decvax!decwrl!turtlevax!ken)
// James A. Woods (decvax!ihnp4!ames!jaw)
// Joe Orost (decvax!vax135!petsd!joe)
int n_bits; // number of bits/code int n_bits; // number of bits/code
int maxbits = BITS; // user settable max # bits/code int maxbits = BITS; // user settable max # bits/code
@ -108,7 +88,7 @@ public class Encoder
0x1FFF, 0x1FFF,
0x3FFF, 0x3FFF,
0x7FFF, 0x7FFF,
0xFFFF }; 0xFFFF};
// Number of characters so far in this 'packet' // Number of characters so far in this 'packet'
int a_count; int a_count;
@ -184,7 +164,8 @@ public class Encoder
output(ClearCode, outs); output(ClearCode, outs);
outer_loop : while ((c = nextPixel()) != EOF) { outer_loop:
while ((c = nextPixel()) != EOF) {
fcode = (c << maxbits) + ent; fcode = (c << maxbits) + ent;
i = (c << hshift) ^ ent; // xor hashing i = (c << hshift) ^ ent; // xor hashing

View File

@ -7,98 +7,87 @@ import java.awt.Graphics2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
* <p>Gif验证码类</p> * Gif验证码类
* * Created by 王帆 on 2018-07-27 上午 10:08.
* @author: wuhongjun
* @version:1.0
*/ */
public class GifCaptcha extends Captcha public class GifCaptcha extends Captcha {
{
public GifCaptcha() public GifCaptcha() {
{
} }
public GifCaptcha(int width,int height){ public GifCaptcha(int width, int height) {
this.width = width; setWidth(width);
this.height = height; setHeight(height);
alphas();
} }
public GifCaptcha(int width,int height,int len){ public GifCaptcha(int width, int height, int len) {
this(width,height); this(width, height);
this.len = len; setLen(len);
} }
public GifCaptcha(int width,int height,int len,Font font) public GifCaptcha(int width, int height, int len, Font font) {
{ this(width, height, len);
this(width,height,len); setFont(font);
this.font = font;
} }
@Override @Override
public void out(OutputStream os) public boolean out(OutputStream os) {
{ checkAlpha();
try boolean ok = false;
{ try {
GifEncoder gifEncoder = new GifEncoder(); // gif编码类这个利用了洋人写的编码类所有类都在附件中 char[] rands = textChar(); // 获取验证码数组
//生成字符 GifEncoder gifEncoder = new GifEncoder();
gifEncoder.start(os); gifEncoder.start(os);
gifEncoder.setQuality(180); gifEncoder.setQuality(180);
gifEncoder.setDelay(100); gifEncoder.setDelay(100);
gifEncoder.setRepeat(0); gifEncoder.setRepeat(0);
BufferedImage frame; BufferedImage frame;
char[] rands = textChar(); Color fontcolor[] = new Color[len];
Color fontcolor[]=new Color[len]; for (int i = 0; i < len; i++) {
for(int i=0;i<len;i++) fontcolor[i] = new Color(20 + num(110), 20 + num(110), 20 + num(110));
{
fontcolor[i]=new Color(20 + num(110), 20 + num(110), 20 + num(110));
} }
for(int i=0;i<len;i++) for (int i = 0; i < len; i++) {
{ frame = graphicsImage(fontcolor, rands, i);
frame=graphicsImage(fontcolor, rands, i);
gifEncoder.addFrame(frame); gifEncoder.addFrame(frame);
frame.flush(); frame.flush();
} }
gifEncoder.finish(); gifEncoder.finish();
}finally ok = true;
{ } finally {
try { try {
os.close(); os.close();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
return ok;
} }
/** /**
* 画随机码图 * 画随机码图
*
* @param fontcolor 随机字体颜色 * @param fontcolor 随机字体颜色
* @param strs 字符数组 * @param strs 字符数组
* @param flag 透明度使用 * @param flag 透明度使用
* @return BufferedImage * @return BufferedImage
*/ */
private BufferedImage graphicsImage(Color[] fontcolor,char[] strs,int flag) private BufferedImage graphicsImage(Color[] fontcolor, char[] strs, int flag) {
{ BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB); Graphics2D g2d = (Graphics2D) image.getGraphics();
//或得图形上下文 g2d.setColor(Color.WHITE); // 填充背景颜色
//Graphics2D g2d=image.createGraphics();
Graphics2D g2d = (Graphics2D)image.getGraphics();
//利用指定颜色填充背景
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height); g2d.fillRect(0, 0, width, height);
AlphaComposite ac3; AlphaComposite ac3;
int h = height - ((height - font.getSize()) >>1) ; int h = height - ((height - font.getSize()) >> 1);
int w = width/len; int w = width / len;
g2d.setFont(font); g2d.setFont(font);
for(int i=0;i<len;i++) for (int i = 0; i < len; i++) {
{
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i)); ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
g2d.setComposite(ac3); g2d.setComposite(ac3);
g2d.setColor(fontcolor[i]); g2d.setColor(fontcolor[i]);
g2d.drawOval(num(width), num(height), 5+num(10), 5+num(10)); g2d.drawOval(num(width), num(height), 5 + num(10), 5 + num(10));
g2d.drawString(strs[i]+"", (width-(len-i)*w)+(w-font.getSize())+1, h-4); g2d.drawString(String.valueOf(strs[i]), (width - (len - i) * w) + (w - font.getSize()) + 1, h - 4);
} }
g2d.dispose(); g2d.dispose();
return image; return image;
@ -106,13 +95,15 @@ public class GifCaptcha extends Captcha
/** /**
* 获取透明度,从0到1,自动计算步长 * 获取透明度,从0到1,自动计算步长
* @return float 透明度 *
* @param i
* @param j
* @return 透明度
*/ */
private float getAlpha(int i,int j) private float getAlpha(int i, int j) {
{ int num = i + j;
int num = i+j; float r = (float) 1 / len, s = (len + 1) * r;
float r = (float)1/len,s = (len+1) * r; return num > len ? (num * r - s) : num * r;
return num > len ? (num *r - s) : num * r;
} }
} }

View File

@ -10,6 +10,7 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
* Gif生成工具
* Class AnimatedGifEncoder - Encodes a GIF file consisting of one or * Class AnimatedGifEncoder - Encodes a GIF file consisting of one or
* more frames. * more frames.
* <pre> * <pre>
@ -25,13 +26,8 @@ import java.io.OutputStream;
* for any purpose, however, refer to the Unisys LZW patent for restrictions * for any purpose, however, refer to the Unisys LZW patent for restrictions
* on use of the associated Encoder class. Please forward any corrections * on use of the associated Encoder class. Please forward any corrections
* to questions at fmsware.com. * to questions at fmsware.com.
*
* @author wuhongjun
* @version 1.03 November 2003
*
*/ */
public class GifEncoder public class GifEncoder {
{
protected int width; // image size protected int width; // image size
protected int height; protected int height;
protected Color transparent = null; // transparent color if given protected Color transparent = null; // transparent color if given
@ -67,6 +63,7 @@ public class GifEncoder
* Sets the GIF frame disposal code for the last added frame * Sets the GIF frame disposal code for the last added frame
* and any subsequent frames. Default is 0 if no transparent * and any subsequent frames. Default is 0 if no transparent
* color has been set, otherwise 2. * color has been set, otherwise 2.
*
* @param code int disposal code. * @param code int disposal code.
*/ */
public void setDispose(int code) { public void setDispose(int code) {
@ -322,7 +319,6 @@ public class GifEncoder
/** /**
* Returns index of palette color closest to c * Returns index of palette color closest to c
*
*/ */
protected int findClosest(Color c) { protected int findClosest(Color c) {
if (colorTab == null) return -1; if (colorTab == null) return -1;
@ -332,7 +328,7 @@ public class GifEncoder
int minpos = 0; int minpos = 0;
int dmin = 256 * 256 * 256; int dmin = 256 * 256 * 256;
int len = colorTab.length; int len = colorTab.length;
for (int i = 0; i < len;) { for (int i = 0; i < len; ) {
int dr = r - (colorTab[i++] & 0xff); int dr = r - (colorTab[i++] & 0xff);
int dg = g - (colorTab[i++] & 0xff); int dg = g - (colorTab[i++] & 0xff);
int db = b - (colorTab[i] & 0xff); int db = b - (colorTab[i] & 0xff);
@ -473,7 +469,7 @@ public class GifEncoder
} }
/** /**
* Write 16-bit value to output stream, LSB first * Write 16-bit value to output stream, LSB first
*/ */
protected void writeShort(int value) throws IOException { protected void writeShort(int value) throws IOException {
out.write(value & 0xff); out.write(value & 0xff);

View File

@ -1,24 +1,20 @@
package com.wf.captcha; package com.wf.captcha;
/** /**
* <p></p>
* *
* @author: wuhongjun
* @version:1.0
*/ */
public class Quant public class Quant {
{
protected static final int netsize = 256; /* number of colours used */ protected static final int netsize = 256; /* number of colours used */
/* four primes near 500 - assume no image has a length so large */ /* four primes near 500 - assume no image has a length so large */
/* that it is divisible by all four primes */ /* that it is divisible by all four primes */
protected static final int prime1 = 499; protected static final int prime1 = 499;
protected static final int prime2 = 491; protected static final int prime2 = 491;
protected static final int prime3 = 487; protected static final int prime3 = 487;
protected static final int prime4 = 503; protected static final int prime4 = 503;
protected static final int minpicturebytes = (3 * prime4); protected static final int minpicturebytes = (3 * prime4);
/* minimum size for input image */ /* minimum size for input image */
/* Program Skeleton /* Program Skeleton
---------------- ----------------
@ -80,13 +76,13 @@ public class Quant
protected int[][] network; /* the network itself - [netsize][4] */ protected int[][] network; /* the network itself - [netsize][4] */
protected int[] netindex = new int[256]; protected int[] netindex = new int[256];
/* for network lookup - really 256 */ /* for network lookup - really 256 */
protected int[] bias = new int[netsize]; protected int[] bias = new int[netsize];
/* bias and freq arrays for learning */ /* bias and freq arrays for learning */
protected int[] freq = new int[netsize]; protected int[] freq = new int[netsize];
protected int[] radpower = new int[initrad]; protected int[] radpower = new int[initrad];
/* radpower for precomputation */ /* radpower for precomputation */
/* Initialise network in range (0,0,0) to (255,255,255) and set parameters /* Initialise network in range (0,0,0) to (255,255,255) and set parameters
----------------------------------------------------------------------- */ ----------------------------------------------------------------------- */
@ -139,7 +135,7 @@ public class Quant
p = network[i]; p = network[i];
smallpos = i; smallpos = i;
smallval = p[1]; /* index on g */ smallval = p[1]; /* index on g */
/* find smallest in i..netsize-1 */ /* find smallest in i..netsize-1 */
for (j = i + 1; j < netsize; j++) { for (j = i + 1; j < netsize; j++) {
q = network[j]; q = network[j];
if (q[1] < smallval) { /* index on g */ if (q[1] < smallval) { /* index on g */
@ -148,7 +144,7 @@ public class Quant
} }
} }
q = network[smallpos]; q = network[smallpos];
/* swap p (i) and q (smallpos) entries */ /* swap p (i) and q (smallpos) entries */
if (i != smallpos) { if (i != smallpos) {
j = q[0]; j = q[0];
q[0] = p[0]; q[0] = p[0];
@ -163,7 +159,7 @@ public class Quant
q[3] = p[3]; q[3] = p[3];
p[3] = j; p[3] = j;
} }
/* smallval entry is now in position i */ /* smallval entry is now in position i */
if (smallval != previouscol) { if (smallval != previouscol) {
netindex[previouscol] = (startpos + i) >> 1; netindex[previouscol] = (startpos + i) >> 1;
for (j = previouscol + 1; j < smallval; j++) for (j = previouscol + 1; j < smallval; j++)
@ -320,6 +316,7 @@ public class Quant
} }
return (best); return (best);
} }
public byte[] process() { public byte[] process() {
learn(); learn();
unbiasnet(); unbiasnet();
@ -385,7 +382,7 @@ public class Quant
---------------------------------------------------- */ ---------------------------------------------------- */
protected void altersingle(int alpha, int i, int b, int g, int r) { protected void altersingle(int alpha, int i, int b, int g, int r) {
/* alter hit neuron */ /* alter hit neuron */
int[] n = network[i]; int[] n = network[i];
n[0] -= (alpha * (n[0] - b)) / initalpha; n[0] -= (alpha * (n[0] - b)) / initalpha;
n[1] -= (alpha * (n[1] - g)) / initalpha; n[1] -= (alpha * (n[1] - g)) / initalpha;
@ -396,10 +393,10 @@ public class Quant
---------------------------- */ ---------------------------- */
protected int contest(int b, int g, int r) { protected int contest(int b, int g, int r) {
/* finds closest neuron (min dist) and updates freq */ /* finds closest neuron (min dist) and updates freq */
/* finds best neuron (min dist-bias) and returns position */ /* finds best neuron (min dist-bias) and returns position */
/* for frequently chosen neurons, freq[i] is high and bias[i] is negative */ /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */
/* bias[i] = gamma*((1/netsize)-freq[i]) */ /* bias[i] = gamma*((1/netsize)-freq[i]) */
int i, dist, a, biasdist, betafreq; int i, dist, a, biasdist, betafreq;
int bestpos, bestbiaspos, bestd, bestbiasd; int bestpos, bestbiaspos, bestd, bestbiasd;

View File

@ -3,41 +3,64 @@ package com.wf.captcha;
import java.util.Random; import java.util.Random;
/** /**
* <p>随机工具类</p> * 随机数工具类
* * Created by 王帆 on 2018-07-27 上午 10:08.
* @author: wuhongjun
* @version:1.0
*/ */
public class Randoms public class Randoms {
{
private static final Random RANDOM = new Random(); private static final Random RANDOM = new Random();
//定义验证码字符.去除了O和I等容易混淆的字母 // 定义验证码字符.去除了O和I等容易混淆的字母
public static final char ALPHA[]={'A','B','C','D','E','F','G','H','G','K','M','N','P','Q','R','S','T','U','V','W','X','Y','Z' public static final char ALPHA[] = {'2', '3', '4', '5', '6', '7', '8', '9',
,'a','b','c','d','e','f','g','h','i','j','k','m','n','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7','8','9'}; 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'G', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
/** /**
* 产生两个数之间的随机数 * 产生两个数之间的随机数
* @param min 小数 *
* @param max 比min大的数 * @param min 最小值
* @return int 随机数字 * @param max 最大值
* @return 随机数
*/ */
public static int num(int min, int max) public static int num(int min, int max) {
{
return min + RANDOM.nextInt(max - min); return min + RANDOM.nextInt(max - min);
} }
/** /**
* 产生0--num的随机数,不包括num * 产生0-num的随机数,不包括num
* @param num 数字 *
* @return int 随机数字 * @param num 最大值
* @return 随机数
*/ */
public static int num(int num) public static int num(int num) {
{
return RANDOM.nextInt(num); return RANDOM.nextInt(num);
} }
public static char alpha() /**
{ * 返回ALPHA中的随机字符
return ALPHA[num(0, ALPHA.length)]; *
* @return 随机字符
*/
public static char alpha() {
return ALPHA[num(ALPHA.length)];
}
/**
* 返回ALPHA中第0位到第num位的随机字符
*
* @param num 到第几位结束
* @return 随机字符
*/
public static char alpha(int num) {
return ALPHA[num(num)];
}
/**
* 返回ALPHA中第min位到第max位的随机字符
*
* @param min 从第几位开始
* @param max 到第几位结束
* @return 随机字符
*/
public static char alpha(int min, int max) {
return ALPHA[num(min, max)];
} }
} }

View File

@ -9,90 +9,93 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
/** /**
* <p>png格式验证码</p> * png格式验证码
* * Created by 王帆 on 2018-07-27 上午 10:08.
* @author: wuhongjun
* @version:1.0
*/ */
public class SpecCaptcha extends Captcha public class SpecCaptcha extends Captcha {
{
public SpecCaptcha() public SpecCaptcha() {
{
} }
public SpecCaptcha(int width, int height)
{ public SpecCaptcha(int width, int height) {
this.width = width; setWidth(width);
this.height = height; setHeight(height);
} }
public SpecCaptcha(int width, int height, int len){
this(width,height); public SpecCaptcha(int width, int height, int len) {
this.len = len; this(width, height);
setLen(len);
} }
public SpecCaptcha(int width, int height, int len, Font font){
this(width,height,len); public SpecCaptcha(int width, int height, int len, Font font) {
this.font = font; this(width, height, len);
} setFont(font);
/**
* 生成验证码
* @throws java.io.IOException IO异常
*/
@Override
public void out(OutputStream out){
graphicsImage(alphas(), out);
} }
/** /**
* 画随机码图 * 生成验证码
* @param strs 文本 *
* @param out 输出流 * @param out 输出流
* @return 是否成功
*/ */
private boolean graphicsImage(char[] strs, OutputStream out){ @Override
boolean ok = false; public boolean out(OutputStream out) {
try checkAlpha();
{ return graphicsImage(textChar(), out);
BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); }
Graphics2D g = (Graphics2D)bi.getGraphics();
/**
* 生成验证码图形
*
* @param strs 验证码
* @param out 输出流
* @return boolean
*/
private boolean graphicsImage(char[] strs, OutputStream out) {
boolean ok;
try {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) bi.getGraphics();
AlphaComposite ac3; AlphaComposite ac3;
Color color ; Color color;
int len = strs.length; int len = strs.length;
g.setColor(Color.WHITE); g.setColor(Color.WHITE);
g.fillRect(0,0,width,height); g.fillRect(0, 0, width, height);
// 随机画干扰的蛋蛋 // 随机画干扰的圆圈
for(int i=0;i<15;i++){ for (int i = 0; i < 15; i++) {
color = color(150, 250); color = color(150, 250);
g.setColor(color); g.setColor(color);
g.drawOval(num(width), num(height), 5+num(10), 5+num(10));// 画蛋蛋有蛋的生活才精彩 g.drawOval(num(width), num(height), 5 + num(10), 5 + num(10));
color = null; color = null;
} }
g.setFont(font); g.setFont(font);
int h = height - ((height - font.getSize()) >>1), int h = height - ((height - font.getSize()) >> 1);
w = width/len, int w = width / len;
size = w-font.getSize()+1; int size = w - font.getSize() + 1;
/* 画字符串 */ // 画字符串
for(int i=0;i<len;i++) for (int i = 0; i < len; i++) {
{
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f);// 指定透明度 ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f);// 指定透明度
g.setComposite(ac3); g.setComposite(ac3);
color = new Color(20 + num(110), 20 + num(110), 20 + num(110));// 对每个字符都用随机颜色 color = new Color(20 + num(110), 20 + num(110), 20 + num(110));// 对每个字符都用随机颜色
g.setColor(color); g.setColor(color);
g.drawString(strs[i]+"",(width-(len-i)*w)+size, h-4); g.drawString(String.valueOf(strs[i]), (width - (len - i) * w) + size, h - 4);
color = null; color = null;
ac3 = null; ac3 = null;
} }
ImageIO.write(bi, "png", out); ImageIO.write(bi, "png", out);
out.flush(); out.flush();
ok = true; ok = true;
}catch (IOException e){ } catch (IOException e) {
ok = false; ok = false;
}finally e.printStackTrace();
{ } finally {
try { try {
out.close(); out.close();
} catch (IOException e) { } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace();
e.printStackTrace(); }
}
} }
return ok; return ok;
} }

View File

@ -11,23 +11,14 @@ import com.wf.captcha.utils.CaptchaUtil;
/** /**
* 验证码servlet * 验证码servlet
* * Created by 王帆 on 2018-07-27 上午 10:08.
* @author wangfan
* @date 2018-5-14 上午9:53:01
*/ */
public class CaptchaServlet extends HttpServlet { public class CaptchaServlet extends HttpServlet {
private static final long serialVersionUID = -90304944339413093L; private static final long serialVersionUID = -90304944339413093L;
public void doGet(HttpServletRequest request, HttpServletResponse response) public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
// 是否有key决定是存在session中还是servletContext中 CaptchaUtil.out(request, response);
String key = request.getParameter("key");
CaptchaUtil cu = new CaptchaUtil();
if (key != null && !key.trim().isEmpty()) {
cu.out(key, request, response);
} else {
cu.out(request, response);
}
} }
public void doPost(HttpServletRequest request, HttpServletResponse response) public void doPost(HttpServletRequest request, HttpServletResponse response)

View File

@ -2,7 +2,6 @@ package com.wf.captcha.utils;
import java.io.IOException; import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -11,136 +10,75 @@ import com.wf.captcha.GifCaptcha;
/** /**
* 图形验证码工具类 * 图形验证码工具类
* * Created by 王帆 on 2018-07-27 上午 10:08.
* @author wangfan
* @date 2018-5-14 上午9:41:06
*/ */
public class CaptchaUtil { public class CaptchaUtil {
private String codeName = "captcha"; private static final String SESSION_KEY = "captcha";
private int width = 130;
private int height = 38;
private int len = 5;
public CaptchaUtil() { /**
} * 验证验证码
*/
public static boolean ver(String code, HttpServletRequest request) {
if (code != null && !code.trim().isEmpty()) {
String captcha = (String) request.getSession().getAttribute(SESSION_KEY);
return code.trim().toLowerCase().equals(captcha);
}
return false;
}
/** /**
* 验证码的宽位数 * 输出验证码
*/ *
public CaptchaUtil(int width, int height, int len) { * @param request
set(width, height, len); * @param response
} * @throws IOException
*/
public static void out(HttpServletRequest request, HttpServletResponse response)
throws IOException {
out(130, 38, 5, request, response);
}
/** /**
* 验证验证码 * 输出验证码
*/ *
public boolean ver(String code, HttpServletRequest request) { * @param len 长度
String captcha = (String) request.getSession().getAttribute(codeName); * @param request
return code.equals(captcha); * @param response
} * @throws IOException
*/
public static void out(int len, HttpServletRequest request, HttpServletResponse response)
throws IOException {
out(130, 38, len, request, response);
}
/** /**
* 验证验证码用于分离的项目 * 输出验证码
*/ *
public boolean ver(String key, String code, HttpServletRequest rq) { * @param width 宽度
ServletContext sc = rq.getServletContext(); * @param height 高度
String keyName = codeName + "-" + key; * @param len 长度
String captcha = (String) sc.getAttribute(keyName); * @param request
return code.equals(captcha); * @param response
} * @throws IOException
*/
public static void out(int width, int height, int len, HttpServletRequest request, HttpServletResponse response)
throws IOException {
setHeader(response);
Captcha captcha = new GifCaptcha(130, 38, 5);
request.getSession().setAttribute(SESSION_KEY, captcha.text().toLowerCase());
captcha.out(response.getOutputStream());
}
/** /**
* 输出验证码 * 设置相应头
*/ *
public void out(HttpServletRequest rq, HttpServletResponse rp) * @param response
throws IOException { */
private static void setHeader(HttpServletResponse response) {
response.setContentType("image/gif");
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
}
setHeader(rp);
// 验证码的宽位数
Captcha captcha = new GifCaptcha(width, height, len);
// 存入缓存
rq.getSession().setAttribute(codeName, captcha.text().toLowerCase());
// 输入图片
captcha.out(rp.getOutputStream());
}
/**
* 输出验证码用于分离项目
*/
public void out(String key, HttpServletRequest rq, HttpServletResponse rp)
throws IOException {
setHeader(rp);
// 验证码的宽位数
Captcha captcha = new GifCaptcha(width, height, len);
// 存入缓存
ServletContext sc = rq.getServletContext();
sc.setAttribute(codeName, captcha.text().toLowerCase());
// 输入图片
captcha.out(rp.getOutputStream());
}
private void setHeader(HttpServletResponse rp) {
rp.setContentType("image/gif");
rp.setHeader("Pragma", "No-cache");
rp.setHeader("Cache-Control", "no-cache");
rp.setDateHeader("Expires", 0);
}
public String getCodeName() {
return codeName;
}
/**
* 设置保存code的key
*/
public void setCodeName(String codeName) {
this.codeName = codeName;
}
public int getWidth() {
return width;
}
/**
* 设置验证码的宽度
*/
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
/**
* 设置验证码的高度
*/
public void setHeight(int height) {
this.height = height;
}
public int getLen() {
return len;
}
/**
* 设置验证码的位数
*/
public void setLen(int len) {
this.len = len;
}
/**
* 设置验证码的宽位数
*/
public void set(int width, int height, int len) {
setWidth(width);
setHeight(height);
setLen(len);
}
} }

View File

@ -0,0 +1,27 @@
package com.wf.captcha;
import org.junit.Test;
import java.io.File;
import java.io.FileOutputStream;
/**
* 测试类
* Created by 王帆 on 2018-07-27 上午 10:08.
*/
public class CaptchaTest {
@Test
public void test() throws Exception {
SpecCaptcha specCaptcha = new SpecCaptcha(150, 40, 4);
System.out.println(specCaptcha.text());
specCaptcha.out(new FileOutputStream(new File("D:/a/aa.png")));
}
@Test
public void testGIf() throws Exception {
GifCaptcha specCaptcha = new GifCaptcha(150, 40, 4);
System.out.println(specCaptcha.text());
specCaptcha.out(new FileOutputStream(new File("D:/a/aa.gif")));
}
}