You could generate CAPTCHA images on your own server without connecting to any external servers as follows:
- Draw text on an image that contains letters and/or numbers.
- Use image processing to distort or camouflage the contents of the image to make it hard for OCR software to correctly read it.
- Display the image on the website, possibly with a secondary mechanism like asking a common-sense question from a question bank.
For the second step (image processing), the company I work for has an image processing Java library that contains hundreds of functions. I took sample images with digits in them and wrote code to perform random distortions on them. The attached image shows 2 input images alongside the output that resulted from running the code on them.
This is the code I used:
public void GenerateCaptcha(RasterImage image) {
Random r = new Random();
// Add some white noise to combat edge detection algorithms
AddNoiseCommand addNoise = new AddNoiseCommand(50 + r.nextInt(50), RasterColorChannel.MASTER);
addNoise.run(image);
int stepDiv = 3;
int xstep = image.getImageWidth() / (stepDiv + r.nextInt(stepDiv));
int ystep = image.getImageHeight() / (stepDiv + r.nextInt(stepDiv));
for (int x = 0; x < image.getImageWidth(); x += xstep)
{
for (int y = 0; y < image.getImageHeight(); y += ystep)
{
xstep = image.getImageWidth() / (stepDiv + r.nextInt(stepDiv));
ystep = image.getImageHeight() / (stepDiv + r.nextInt(stepDiv));
LeadRect rect = new LeadRect();
rect.setLeft(x - xstep);
rect.setTop(y - ystep);
xstep = image.getImageWidth() * 2 / (stepDiv + r.nextInt(stepDiv));
ystep = image.getImageHeight() * 2 / (stepDiv + r.nextInt(stepDiv));
rect.setWidth(xstep);
rect.setHeight(ystep);
image.addEllipseToRegion(null, rect, RasterRegionCombineMode.SET);
InvertCommand invert = new InvertCommand();
int brightness = r.nextInt(400) - 200;
ChangeIntensityCommand intensity = new ChangeIntensityCommand(brightness);
intensity.run(image);
invert.run(image);
ystep = image.getImageHeight() / (stepDiv + r.nextInt(stepDiv));
}
xstep = image.getImageWidth() / (stepDiv + r.nextInt(stepDiv));
}
image.makeRegionEmpty();
// Add a bit more white noise
addNoise.run(image);
}
If you would like to try the library, there’s a free evaluation edition on this page.