Problem
SpecCaptcha (and the other captcha types) always render on an opaque white
background: the background is filled with Color.WHITE on a BufferedImage of type
TYPE_INT_RGB (no alpha channel), inside a private graphicsImage(...) method.
Because that method is private and the background colour/image type are hard-coded, there
is no way to get a captcha PNG with a transparent background through configuration or
subclassing — the only option is to re-implement the whole rendering.
Use case: we embed the image captcha directly on a page and want the page background to
show through instead of a white box.
How we worked around it
We had to subclass SpecCaptcha and fully re-implement out(OutputStream), mirroring the
original glyph + interference-line layout, but drawing onto a TYPE_INT_ARGB image with
no background fill:
public class TransparentSpecCaptcha extends SpecCaptcha {
public TransparentSpecCaptcha(int width, int height, int len) {
super(width, height, len);
}
@Override
public boolean out(OutputStream os) {
char[] strs = textChar();
int w = getWidth(), h = getHeight();
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) bi.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// No background fill -> stays transparent.
for (int i = 0; i < 5; i++) {
drawBesselLine(1, g);
}
g.setFont(getFont());
FontMetrics fm = g.getFontMetrics();
int charWidth = w / strs.length;
int leftPadding = (charWidth - (int) fm.getStringBounds("W", g).getWidth()) / 2;
for (int i = 0; i < strs.length; i++) {
g.setColor(color());
String s = String.valueOf(strs[i]);
int y = h - ((h - (int) fm.getStringBounds(s, g).getHeight()) >> 1);
g.drawString(s, i * charWidth + leftPadding + 3, y - 3);
}
g.dispose();
try {
ImageIO.write(bi, "png", os);
os.flush();
return true;
} catch (IOException e) {
return false;
}
}
}
Problem
SpecCaptcha(and the other captcha types) always render on an opaque whitebackground: the background is filled with
Color.WHITEon aBufferedImageof typeTYPE_INT_RGB(no alpha channel), inside a privategraphicsImage(...)method.Because that method is private and the background colour/image type are hard-coded, there
is no way to get a captcha PNG with a transparent background through configuration or
subclassing — the only option is to re-implement the whole rendering.
Use case: we embed the image captcha directly on a page and want the page background to
show through instead of a white box.
How we worked around it
We had to subclass
SpecCaptchaand fully re-implementout(OutputStream), mirroring theoriginal glyph + interference-line layout, but drawing onto a
TYPE_INT_ARGBimage withno background fill: