/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.utils;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.servlet.ServletContext;
import nl.strohalm.cyclos.CyclosConfiguration;
import nl.strohalm.cyclos.entities.customization.images.Image;
import nl.strohalm.cyclos.entities.customization.images.Image.Nature;
import nl.strohalm.cyclos.utils.customizedfile.CustomizedFileHandler;
import nl.strohalm.cyclos.utils.customizedfile.ImageChangeListener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.context.ServletContextAware;
import com.google.code.kaptcha.GimpyEngine;
import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.text.WordRenderer;
import com.google.code.kaptcha.util.Config;
/**
* Custom captcha producer which is based in a background image
* @author luis
*/
public class CaptchaProducer implements Producer, ServletContextAware, InitializingBean {
private BufferedImage background;
private WordRenderer wordRenderer;
private GimpyEngine gimpyEngine;
private Config config;
private ServletContext servletContext;
private CustomizedFileHandler customizedFileHandler;
@Override
public void afterPropertiesSet() throws Exception {
config = new Config(CyclosConfiguration.getCyclosProperties());
wordRenderer = config.getWordRendererImpl();
gimpyEngine = config.getObscurificatorImpl();
customizedFileHandler.addImageChangeListener(new ImageChangeListener() {
@Override
public void onImageChanged(final Image image) {
if (image.getNature() == Nature.SYSTEM && image.getName().contains("captchaBackground")) {
// Whenever the captcha background has changed, set the cached image to null, so that it's reloaded again
background = null;
}
}
});
}
@Override
public BufferedImage createImage(final String text) {
final BufferedImage background = readBackground();
BufferedImage image = wordRenderer.renderWord(text, background.getWidth(), background.getHeight());
image = gimpyEngine.getDistortedImage(image);
return combine(image, background);
}
@Override
public String createText() {
return config.getTextProducerImpl().getText();
}
public void setCustomizedFileHandler(final CustomizedFileHandler customizedFileHandler) {
this.customizedFileHandler = customizedFileHandler;
}
@Override
public void setServletContext(final ServletContext servletContext) {
this.servletContext = servletContext;
}
/**
* Draws the image over the background
*/
private BufferedImage combine(final BufferedImage image, final BufferedImage background) {
final int width = background.getWidth();
final int height = background.getHeight();
// Create the new combined image
final BufferedImage imageWithBackground = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D graph = (Graphics2D) imageWithBackground.getGraphics();
final RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
hints.add(new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY));
hints.add(new RenderingHints(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY));
hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
graph.setRenderingHints(hints);
graph.fill(new Rectangle2D.Double(0, 0, width, height));
// draw the image over the background
graph.drawImage(background, 0, 0, null);
graph.drawImage(image, 0, 0, null);
return imageWithBackground;
}
private BufferedImage readBackground() {
if (background == null) {
try {
final URL backgroundUrl = servletContext.getResource("/pages/images/captchaBackground.jpg");
background = ImageIO.read(backgroundUrl);
} catch (final Exception e) {
throw new IllegalStateException("Could not read captcha background image");
}
}
return background;
}
}