카테고리 없음
How to get Random CAPTCHA images dynamically.
[czar]
2014. 5. 29. 17:56
How to get Random CAPTCHA images dynamically.
Html Page:(captcha.jsp)
<img src="/registerCaptcha" width="72" height="26" alt="captcha" class="captcha-border" />
Struts-config.xml
<action path="/registerCaptcha" type="com.captcha.RegisterCaptchaAction">
<forward name="shRegisterCaptcha" path="/jsp/common/captcha.jsp"/>
</action>
Struts Action Class
package com.captcha;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class RegisterCaptchaAction extends org.apache.struts.action.Action {
Log log = LogFactory.getLog(RegisterCaptchaAction.class);
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setDateHeader("Max-Age", 0);
response.setContentType("image/jpg");
BufferedImage bufferedImage = null;
Graphics2D g = null;
try {
Color textColor = Color.decode("#2e2e2e");
Font textFont = new Font("arial Tahoma Sans-serif", Font.BOLD, 22);
int charsToPrint = 5;
int width = request.getParameter("width") != null ? Integer.parseInt(request.getParameter("width")) : 150;
int height = request.getParameter("height") != null ? Integer.parseInt(request.getParameter("height")) : 35;
float horizMargin = 12.0f;
float imageQuality = 1.0f; // max is 1.0 (this is for jpeg)
double rotationRange = 0.1; // this is radians
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) bufferedImage.getGraphics();
//Draw an oval
//g.setColor(Color.decode("#ECEAEA"));
g.fillRect(0, 0, width, height);
g.setColor(textColor);
g.setFont(textFont);
FontMetrics fontMetrics = g.getFontMetrics();
int maxAdvance = fontMetrics.getMaxAdvance();
int fontHeight = fontMetrics.getHeight();
// i removed 1 and l and i because there are confusing to users...
// Z, z, and N also get confusing when rotated
// 0, O, and o are also confusing...
// lowercase G looks a lot like a 9 so i killed it
// this should ideally be done for every language...
// i like controlling the characters though because it helps prevent confusion
String elegibleChars = "ABCDEFGHJKLMPQRSTUVWXY23456789";
//String elegibleChars = "AEFHKLPRTX12345678";
//String elegibleChars = "0123456789";
char[] chars = elegibleChars.toCharArray();
float spaceForLetters = -horizMargin * 5 + width;
float spacePerChar = spaceForLetters / (charsToPrint - 1.5f);
AffineTransform transform = g.getTransform();
StringBuffer finalString = new StringBuffer();
for (int i = 0; i < charsToPrint; i++) {
double randomValue = Math.random();
int randomIndex = (int) Math.round(randomValue * (chars.length - 1));
char characterToShow = chars[randomIndex];
finalString.append(characterToShow);
// this is a separate canvas used for the character so that
// we can rotate it independently
int charImageWidth = maxAdvance * 2;
int charImageHeight = fontHeight * 2;
int charWidth = fontMetrics.charWidth(characterToShow);
int charDim = Math.max(maxAdvance, fontHeight);
int halfCharDim = (int) (charDim / 2);
BufferedImage charImage = null;
Graphics2D charGraphics = null;
try {
charImage = new BufferedImage(charDim, charDim, BufferedImage.TYPE_INT_ARGB);
charGraphics = charImage.createGraphics();
charGraphics.translate(halfCharDim, halfCharDim);
double angle = (Math.random() - 0.5) * rotationRange;
charGraphics.transform(AffineTransform.getRotateInstance(angle));
charGraphics.translate(-halfCharDim, -halfCharDim);
charGraphics.setColor(textColor);
charGraphics.setFont(textFont);
int charX = (int) (0.5 * charDim - 0.5 * charWidth);
charGraphics.drawString("" + characterToShow, charX,
(int) ((charDim - fontMetrics.getAscent())
/ 2 + fontMetrics.getAscent()));
float x = horizMargin + spacePerChar * (i) - charDim / 4.0f;
int y = (int) ((height - charDim) / 2);
//System.out.println("x=" + x + " height=" + height + " charDim=" + charDim + " y=" + y + " advance=" + maxAdvance + " fontHeight=" + fontHeight + " ascent=" + fontMetrics.getAscent());
g.drawImage(charImage, (int) x, y, charDim, charDim, null, null);
} finally {
try {
charGraphics.dispose();
} catch (Exception ex) {
}
try {
charImage.flush();
} catch (Exception ex) {
}
}
}
log.info("captcha string : " + finalString);
//Write the image as a jpg
Iterator iter = ImageIO.getImageWritersByFormatName("JPG");
if (iter.hasNext()) {
ImageWriter writer = null;
javax.imageio.stream.ImageOutputStream imageOutputStream = null;
javax.servlet.ServletOutputStream servletOutputStream = null;
try {
writer = (ImageWriter) iter.next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(imageQuality);
servletOutputStream = response.getOutputStream();
imageOutputStream = ImageIO.createImageOutputStream(servletOutputStream);
writer.setOutput(imageOutputStream);
IIOImage imageIO = new IIOImage(bufferedImage, null, null);
writer.write(null, imageIO, iwp);
} catch (Exception ex) {
writer.abort();
} finally {//modified to prevent too many open files error
if (writer != null) {
writer.dispose();
}
try {
imageOutputStream.close();
} catch (Exception ex) {
}
try {
servletOutputStream.close();
} catch (Exception ex) {
}
}
} else {
log.error("CaptchaErr No Encoder Found For JSP");
throw new RuntimeException("no encoder found for jsp");
}
//ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
// let's stick the final string in the session
request.getSession(true).setAttribute("postCouponCaptcha", finalString.toString());
} catch (Exception ioe) {
log.error("Captcha Error : " + ioe.getMessage());
throw new RuntimeException("Unable to build image", ioe);
} finally {
try {
g.dispose();
} catch (Exception ex) {
}
try {
bufferedImage.flush();
} catch (Exception ex) {
}
}
return mapping.findForward("shRegisterCaptcha");
}
}
<img src="/registerCaptcha" width="72" height="26" alt="captcha" class="captcha-border" />
Struts-config.xml
<action path="/registerCaptcha" type="com.captcha.RegisterCaptchaAction">
<forward name="shRegisterCaptcha" path="/jsp/common/captcha.jsp"/>
</action>
Struts Action Class
package com.captcha;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public class RegisterCaptchaAction extends org.apache.struts.action.Action {
Log log = LogFactory.getLog(RegisterCaptchaAction.class);
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setDateHeader("Max-Age", 0);
response.setContentType("image/jpg");
BufferedImage bufferedImage = null;
Graphics2D g = null;
try {
Color textColor = Color.decode("#2e2e2e");
Font textFont = new Font("arial Tahoma Sans-serif", Font.BOLD, 22);
int charsToPrint = 5;
int width = request.getParameter("width") != null ? Integer.parseInt(request.getParameter("width")) : 150;
int height = request.getParameter("height") != null ? Integer.parseInt(request.getParameter("height")) : 35;
float horizMargin = 12.0f;
float imageQuality = 1.0f; // max is 1.0 (this is for jpeg)
double rotationRange = 0.1; // this is radians
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) bufferedImage.getGraphics();
//Draw an oval
//g.setColor(Color.decode("#ECEAEA"));
g.fillRect(0, 0, width, height);
g.setColor(textColor);
g.setFont(textFont);
FontMetrics fontMetrics = g.getFontMetrics();
int maxAdvance = fontMetrics.getMaxAdvance();
int fontHeight = fontMetrics.getHeight();
// i removed 1 and l and i because there are confusing to users...
// Z, z, and N also get confusing when rotated
// 0, O, and o are also confusing...
// lowercase G looks a lot like a 9 so i killed it
// this should ideally be done for every language...
// i like controlling the characters though because it helps prevent confusion
String elegibleChars = "ABCDEFGHJKLMPQRSTUVWXY23456789";
//String elegibleChars = "AEFHKLPRTX12345678";
//String elegibleChars = "0123456789";
char[] chars = elegibleChars.toCharArray();
float spaceForLetters = -horizMargin * 5 + width;
float spacePerChar = spaceForLetters / (charsToPrint - 1.5f);
AffineTransform transform = g.getTransform();
StringBuffer finalString = new StringBuffer();
for (int i = 0; i < charsToPrint; i++) {
double randomValue = Math.random();
int randomIndex = (int) Math.round(randomValue * (chars.length - 1));
char characterToShow = chars[randomIndex];
finalString.append(characterToShow);
// this is a separate canvas used for the character so that
// we can rotate it independently
int charImageWidth = maxAdvance * 2;
int charImageHeight = fontHeight * 2;
int charWidth = fontMetrics.charWidth(characterToShow);
int charDim = Math.max(maxAdvance, fontHeight);
int halfCharDim = (int) (charDim / 2);
BufferedImage charImage = null;
Graphics2D charGraphics = null;
try {
charImage = new BufferedImage(charDim, charDim, BufferedImage.TYPE_INT_ARGB);
charGraphics = charImage.createGraphics();
charGraphics.translate(halfCharDim, halfCharDim);
double angle = (Math.random() - 0.5) * rotationRange;
charGraphics.transform(AffineTransform.getRotateInstance(angle));
charGraphics.translate(-halfCharDim, -halfCharDim);
charGraphics.setColor(textColor);
charGraphics.setFont(textFont);
int charX = (int) (0.5 * charDim - 0.5 * charWidth);
charGraphics.drawString("" + characterToShow, charX,
(int) ((charDim - fontMetrics.getAscent())
/ 2 + fontMetrics.getAscent()));
float x = horizMargin + spacePerChar * (i) - charDim / 4.0f;
int y = (int) ((height - charDim) / 2);
//System.out.println("x=" + x + " height=" + height + " charDim=" + charDim + " y=" + y + " advance=" + maxAdvance + " fontHeight=" + fontHeight + " ascent=" + fontMetrics.getAscent());
g.drawImage(charImage, (int) x, y, charDim, charDim, null, null);
} finally {
try {
charGraphics.dispose();
} catch (Exception ex) {
}
try {
charImage.flush();
} catch (Exception ex) {
}
}
}
log.info("captcha string : " + finalString);
//Write the image as a jpg
Iterator iter = ImageIO.getImageWritersByFormatName("JPG");
if (iter.hasNext()) {
ImageWriter writer = null;
javax.imageio.stream.ImageOutputStream imageOutputStream = null;
javax.servlet.ServletOutputStream servletOutputStream = null;
try {
writer = (ImageWriter) iter.next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(imageQuality);
servletOutputStream = response.getOutputStream();
imageOutputStream = ImageIO.createImageOutputStream(servletOutputStream);
writer.setOutput(imageOutputStream);
IIOImage imageIO = new IIOImage(bufferedImage, null, null);
writer.write(null, imageIO, iwp);
} catch (Exception ex) {
writer.abort();
} finally {//modified to prevent too many open files error
if (writer != null) {
writer.dispose();
}
try {
imageOutputStream.close();
} catch (Exception ex) {
}
try {
servletOutputStream.close();
} catch (Exception ex) {
}
}
} else {
log.error("CaptchaErr No Encoder Found For JSP");
throw new RuntimeException("no encoder found for jsp");
}
//ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
// let's stick the final string in the session
request.getSession(true).setAttribute("postCouponCaptcha", finalString.toString());
} catch (Exception ioe) {
log.error("Captcha Error : " + ioe.getMessage());
throw new RuntimeException("Unable to build image", ioe);
} finally {
try {
g.dispose();
} catch (Exception ex) {
}
try {
bufferedImage.flush();
} catch (Exception ex) {
}
}
return mapping.findForward("shRegisterCaptcha");
}
}