93 lines
3.1 KiB
Java
93 lines
3.1 KiB
Java
package lc.captchas;
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Font;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.image.BufferedImage;
|
|
import java.awt.image.ConvolveOp;
|
|
import java.awt.image.Kernel;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import lc.captchas.interfaces.Challenge;
|
|
import lc.captchas.interfaces.ChallengeProvider;
|
|
import lc.misc.HelperFunctions;
|
|
import lc.misc.PngImageWriter;
|
|
|
|
public class ShadowTextCaptcha implements ChallengeProvider {
|
|
|
|
public String getId() {
|
|
return "ShadowTextCaptcha";
|
|
}
|
|
|
|
public void configure(String config) {
|
|
// TODO: Add custom config
|
|
}
|
|
|
|
public Map<String, List<String>> supportedParameters() {
|
|
return Map.of(
|
|
"supportedLevels", List.of("easy"),
|
|
"supportedMedia", List.of("image/png"),
|
|
"supportedInputType", List.of("text"));
|
|
}
|
|
|
|
public boolean checkAnswer(String secret, String answer) {
|
|
return answer.toLowerCase().equals(secret);
|
|
}
|
|
|
|
private float[] makeKernel(int size) {
|
|
final int N = size * size;
|
|
final float weight = 1.0f / (N);
|
|
final float[] kernel = new float[N];
|
|
java.util.Arrays.fill(kernel, weight);
|
|
return kernel;
|
|
};
|
|
|
|
private byte[] shadowText(final int width, final int height, String text) {
|
|
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
|
final int fontHeight = (int) (height * 0.5f);
|
|
Font font = new Font("Arial", Font.PLAIN, fontHeight);
|
|
Graphics2D graphics2D = img.createGraphics();
|
|
HelperFunctions.setRenderingHints(graphics2D);
|
|
graphics2D.setPaint(Color.WHITE);
|
|
graphics2D.fillRect(0, 0, width, height);
|
|
graphics2D.setPaint(Color.BLACK);
|
|
graphics2D.setFont(font);
|
|
final var stringWidth = graphics2D.getFontMetrics().stringWidth(text);
|
|
final var padding = (stringWidth > width) ? 0 : (width - stringWidth) / 2;
|
|
final var scaleX = (stringWidth > width) ? width / ((double) stringWidth) : 1d;
|
|
graphics2D.scale(scaleX, 1d);
|
|
graphics2D.drawString(text, padding, fontHeight * 1.1f);
|
|
graphics2D.dispose();
|
|
final int kernelSize = (int) Math.ceil((Math.min(width, height) / 50.0));
|
|
ConvolveOp op =
|
|
new ConvolveOp(
|
|
new Kernel(kernelSize, kernelSize, makeKernel(kernelSize)),
|
|
ConvolveOp.EDGE_NO_OP,
|
|
null);
|
|
BufferedImage img2 = op.filter(img, null);
|
|
Graphics2D g2d = img2.createGraphics();
|
|
HelperFunctions.setRenderingHints(g2d);
|
|
g2d.setPaint(Color.WHITE);
|
|
g2d.scale(scaleX, 1d);
|
|
g2d.setFont(font);
|
|
g2d.drawString(text, padding - kernelSize, fontHeight * 1.1f);
|
|
g2d.dispose();
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
try {
|
|
PngImageWriter.write(baos, img2);
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
return baos.toByteArray();
|
|
}
|
|
|
|
public Challenge returnChallenge(String level, String size) {
|
|
String secret = HelperFunctions.randomString(6);
|
|
final int[] size2D = HelperFunctions.parseSize2D(size);
|
|
final int width = size2D[0];
|
|
final int height = size2D[1];
|
|
return new Challenge(shadowText(width, height, secret), "image/png", secret.toLowerCase());
|
|
}
|
|
}
|