cn.apiclub.captcha.Captcha Maven / Gradle / Ivy
The newest version!
package cn.apiclub.captcha;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
import javax.imageio.ImageIO;
import cn.apiclub.captcha.backgrounds.BackgroundProducer;
import cn.apiclub.captcha.backgrounds.TransparentBackgroundProducer;
import cn.apiclub.captcha.gimpy.GimpyRenderer;
import cn.apiclub.captcha.gimpy.RippleGimpyRenderer;
import cn.apiclub.captcha.noise.CurvedLineNoiseProducer;
import cn.apiclub.captcha.noise.NoiseProducer;
import cn.apiclub.captcha.text.producer.DefaultTextProducer;
import cn.apiclub.captcha.text.producer.TextProducer;
import cn.apiclub.captcha.text.renderer.DefaultWordRenderer;
import cn.apiclub.captcha.text.renderer.WordRenderer;
/**
* A builder for generating a CAPTCHA image/answer pair.
*
*
* Example for generating a new CAPTCHA:
*
* Captcha captcha = new Captcha.Builder(200, 50)
* .addText()
* .addBackground()
* .build();
* Note that the build()
must always be called last. Other methods are optional,
* and can sometimes be repeated. For example:
* Captcha captcha = new Captcha.Builder(200, 50)
* .addText()
* .addNoise()
* .addNoise()
* .addNoise()
* .addBackground()
* .build();
* Adding multiple backgrounds has no affect; the last background added will simply be the
* one that is eventually rendered.
* To validate that answerStr
is a correct answer to the CAPTCHA:
*
* captcha.isCorrect(answerStr);
*
* @author James Childers
*
*/
public final class Captcha implements Serializable {
private static final long serialVersionUID = 617511236L;
public static final String NAME = "simpleCaptcha";
private Builder _builder;
private Captcha(Builder builder) {
_builder = builder;
}
public static class Builder implements Serializable {
private static final long serialVersionUID = 12L;
/**
* @serial
*/
private String _answer = "";
/**
* @serial
*/
private BufferedImage _img;
/**
* @serial
*/
private BufferedImage _bg;
/**
* @serial
*/
private Date _timeStamp;
private boolean _addBorder = false;
public Builder(int width, int height) {
_img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
/**
* Add a background using the default {@link BackgroundProducer} (a {@link TransparentBackgroundProducer}).
*/
public Builder addBackground() {
return addBackground(new TransparentBackgroundProducer());
}
/**
* Add a background using the given {@link BackgroundProducer}.
*
* @param bgProd
*/
public Builder addBackground(BackgroundProducer bgProd) {
_bg = bgProd.getBackground(_img.getWidth(), _img.getHeight());
return this;
}
/**
* Generate the answer to the CAPTCHA using the {@link DefaultTextProducer}.
*/
public Builder addText() {
return addText(new DefaultTextProducer());
}
/**
* Generate the answer to the CAPTCHA using the given
* {@link TextProducer}.
*
* @param txtProd
*/
public Builder addText(TextProducer txtProd) {
return addText(txtProd, new DefaultWordRenderer());
}
/**
* Generate the answer to the CAPTCHA using the default
* {@link TextProducer}, and render it to the image using the given
* {@link WordRenderer}.
*
* @param wRenderer
*/
public Builder addText(WordRenderer wRenderer) {
return addText(new DefaultTextProducer(), wRenderer);
}
/**
* Generate the answer to the CAPTCHA using the given
* {@link TextProducer}, and render it to the image using the given
* {@link WordRenderer}.
*
* @param txtProd
* @param wRenderer
*/
public Builder addText(TextProducer txtProd, WordRenderer wRenderer) {
_answer += txtProd.getText();
wRenderer.render(_answer, _img);
return this;
}
/**
* Add noise using the default {@link NoiseProducer} (a {@link CurvedLineNoiseProducer}).
*/
public Builder addNoise() {
return this.addNoise(new CurvedLineNoiseProducer());
}
/**
* Add noise using the given NoiseProducer.
*
* @param nProd
*/
public Builder addNoise(NoiseProducer nProd) {
nProd.makeNoise(_img);
return this;
}
/**
* Gimp the image using the default {@link GimpyRenderer} (a {@link RippleGimpyRenderer}).
*/
public Builder gimp() {
return gimp(new RippleGimpyRenderer());
}
/**
* Gimp the image using the given {@link GimpyRenderer}.
*
* @param gimpy
*/
public Builder gimp(GimpyRenderer gimpy) {
gimpy.gimp(_img);
return this;
}
/**
* Draw a single-pixel wide black border around the image.
*/
public Builder addBorder() {
_addBorder = true;
return this;
}
/**
* Build the CAPTCHA. This method should always be called, and should always
* be called last.
*
* @return The constructed CAPTCHA.
*/
public Captcha build() {
if (_bg == null) {
_bg = new TransparentBackgroundProducer().getBackground(_img.getWidth(), _img.getHeight());
}
// Paint the main image over the background
Graphics2D g = _bg.createGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
g.drawImage(_img, null, null);
if (_addBorder) {
int width = _img.getWidth();
int height = _img.getHeight();
g.setColor(Color.BLACK);
g.drawLine(0, 0, 0, width);
g.drawLine(0, 0, width, 0);
g.drawLine(0, height - 1, width, height - 1);
g.drawLine(width - 1, height - 1, width - 1, 0);
}
_img = _bg;
_timeStamp = new Date();
return new Captcha(this);
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[Answer: ");
sb.append(_answer);
sb.append("][Timestamp: ");
sb.append(_timeStamp);
sb.append("][Image: ");
sb.append(_img);
sb.append("]");
return sb.toString();
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(_answer);
out.writeObject(_timeStamp);
ImageIO.write(_img, "png", ImageIO.createImageOutputStream(out));
}
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
_answer = (String) in.readObject();
_timeStamp = (Date) in.readObject();
_img = ImageIO.read(ImageIO.createImageInputStream(in));
}
}
public boolean isCorrect(String answer) {
return answer.equals(_builder._answer);
}
public String getAnswer() {
return _builder._answer;
}
/**
* Get the CAPTCHA image, a PNG.
*
* @return A PNG CAPTCHA image.
*/
public BufferedImage getImage() {
return _builder._img;
}
public Date getTimeStamp() {
return new Date(_builder._timeStamp.getTime());
}
@Override
public String toString() {
return _builder.toString();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy