在 java 中将随机文本转换为具有随机噪声的图像
convert Random text to image with random noise in java
我正在我们的项目中实现验证码功能。它基本上是 Tapestry 框架应用程序。我正在生成随机字母数字字符串并将其转换为图像并在网页中显示。
现在我需要的是,我想添加随机噪声,如点线等,使带有文字的图像不清晰。如何进行请帮忙。
保留代码以供参考。
-- 此方法给出文本验证码。
`
public String generateCaptcha() {
Random random = new Random();
int min = 4; // Inclusive
int max = 9; // Exclusive
int length = random.nextInt(max-min) + min;
StringBuilder captchaStringBuffer = new StringBuilder();
for (int i = 0; i < length; i++) {
int captchaNumber = Math.abs(random.nextInt()) % 60;
int charNumber = 0;
if (captchaNumber < 26) {
charNumber = 65 + captchaNumber;
}
else if (captchaNumber < 52){
charNumber = 97 + (captchaNumber - 26);
}
else {
charNumber = 48 + (captchaNumber - 52);
}
captchaStringBuffer.append((char)charNumber);
}
return captchaStringBuffer.toString();
}
`
-- 此方法将生成的验证码转换为没有任何噪声的图像。
`
public void textToImage(String displayCode){
String text = displayCode;
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = new Font("Arial", Font.PLAIN, 48);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int width = fm.stringWidth(text);
int height = fm.getHeight();
g2d.dispose();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_DISABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_DEFAULT);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, "png", baos);
byte[] res=baos.toByteArray();
setBinaryImage("data:image/png;base64,"+Base64.encode(res));
} catch (IOException e) {
}
}
`
我是新手,所以请说清楚。
提前致谢:-)
当试图遮挡正在显示的文本时,您可以使用:
- Dots/Circles,以不同的大小和颜色随机分布在图像上
- 线条,从图像边缘的一个随机点到图像边缘的另一个点。这些也可以在颜色和厚度上有所不同。
据我所知,你可以用g2d.drawLine(x1, y1, x2, y2)
画一条线。既然你想让它从边上走到边上的另一个点,你就得限制你的random-point-generation。您可以使用这种方法:
public Point pointOnEdge(int width, int height) {
int side = (int) (Math.random() * 3); //0=top, 1=bot, 2=left, 3=right
int x = 0;
int y = 0;
switch(side) {
case 0:
//when on top, y is at the top of the image (0) and x is something in [0, width]
y = 0;
x = (int) (Math.random() * width);
break;
case 1:
//when on bottom, y is at the bottom of the image (image height) and x is something in [0, width]
y = height;
x = (int) (Math.random() * width);
case 2:
//when on left, x is at the left side (0) of the image and y is something in [0, height]
y = (int) (Math.random() * height);
x = 0;
break;
case 3:
//when on left, x is at the left side (0) of the image and y is something in [0, height]
y = (int) (Math.random() * height);
x = width;
break;
}
return new Point(x, y);
}
如果你像这样创建两个点,并用一条线将它们连接起来,那么你就有了一种非常简单的方法来部分阻挡你的图像,从而扭曲它。
现在进入圈子:
public void drawCircles(Graphics2D g2d, int width, int height) {
//draw 10 of them
for(int i = 0; i < 10; i++) {
//select a random size
int x = 10 + (int) (Math.random() * 10);
//draw circle at random position with the created size
g2d.fillOval((int) (Math.random() * width), (int) (Math.random() * height), x, x);
}
}
像这样,您现在可以扭曲图像以使其难以阅读。
我希望您对通用代码有足够的了解,知道将这些函数调用放在哪里。如果没有,有需要我可以补充
编辑 1
如果您想要验证码的点状背景,您可以在呈现字符串或其他任何内容之前使用此代码:
boolean r = false;
boolean g = false;
for(int y = 0; y < height; y++) {
r = !r;
g = r;
for(int x = 0; x < width; x++) {
g = !g;
if(g) {
g2d.setColor(Color.GRAY);
}else {
g2d.setColor(Color.WHITE);
}
g2d.drawLine(x, y, x, y);
}
}
编辑 2
我建议您使用不同的字体。然后你不必做任何拉伸。好的字体是例如吉吉。您也可以 select 随机使用 GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()
一种字体,其中 returns Java 拥有的所有字体。
我正在我们的项目中实现验证码功能。它基本上是 Tapestry 框架应用程序。我正在生成随机字母数字字符串并将其转换为图像并在网页中显示。
现在我需要的是,我想添加随机噪声,如点线等,使带有文字的图像不清晰。如何进行请帮忙。
保留代码以供参考。
-- 此方法给出文本验证码。
`
public String generateCaptcha() {
Random random = new Random();
int min = 4; // Inclusive
int max = 9; // Exclusive
int length = random.nextInt(max-min) + min;
StringBuilder captchaStringBuffer = new StringBuilder();
for (int i = 0; i < length; i++) {
int captchaNumber = Math.abs(random.nextInt()) % 60;
int charNumber = 0;
if (captchaNumber < 26) {
charNumber = 65 + captchaNumber;
}
else if (captchaNumber < 52){
charNumber = 97 + (captchaNumber - 26);
}
else {
charNumber = 48 + (captchaNumber - 52);
}
captchaStringBuffer.append((char)charNumber);
}
return captchaStringBuffer.toString();
}
`
-- 此方法将生成的验证码转换为没有任何噪声的图像。
`
public void textToImage(String displayCode){
String text = displayCode;
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = new Font("Arial", Font.PLAIN, 48);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int width = fm.stringWidth(text);
int height = fm.getHeight();
g2d.dispose();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_DISABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_DEFAULT);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, "png", baos);
byte[] res=baos.toByteArray();
setBinaryImage("data:image/png;base64,"+Base64.encode(res));
} catch (IOException e) {
}
}
`
我是新手,所以请说清楚。
提前致谢:-)
当试图遮挡正在显示的文本时,您可以使用:
- Dots/Circles,以不同的大小和颜色随机分布在图像上
- 线条,从图像边缘的一个随机点到图像边缘的另一个点。这些也可以在颜色和厚度上有所不同。
据我所知,你可以用g2d.drawLine(x1, y1, x2, y2)
画一条线。既然你想让它从边上走到边上的另一个点,你就得限制你的random-point-generation。您可以使用这种方法:
public Point pointOnEdge(int width, int height) {
int side = (int) (Math.random() * 3); //0=top, 1=bot, 2=left, 3=right
int x = 0;
int y = 0;
switch(side) {
case 0:
//when on top, y is at the top of the image (0) and x is something in [0, width]
y = 0;
x = (int) (Math.random() * width);
break;
case 1:
//when on bottom, y is at the bottom of the image (image height) and x is something in [0, width]
y = height;
x = (int) (Math.random() * width);
case 2:
//when on left, x is at the left side (0) of the image and y is something in [0, height]
y = (int) (Math.random() * height);
x = 0;
break;
case 3:
//when on left, x is at the left side (0) of the image and y is something in [0, height]
y = (int) (Math.random() * height);
x = width;
break;
}
return new Point(x, y);
}
如果你像这样创建两个点,并用一条线将它们连接起来,那么你就有了一种非常简单的方法来部分阻挡你的图像,从而扭曲它。
现在进入圈子:
public void drawCircles(Graphics2D g2d, int width, int height) {
//draw 10 of them
for(int i = 0; i < 10; i++) {
//select a random size
int x = 10 + (int) (Math.random() * 10);
//draw circle at random position with the created size
g2d.fillOval((int) (Math.random() * width), (int) (Math.random() * height), x, x);
}
}
像这样,您现在可以扭曲图像以使其难以阅读。 我希望您对通用代码有足够的了解,知道将这些函数调用放在哪里。如果没有,有需要我可以补充
编辑 1
如果您想要验证码的点状背景,您可以在呈现字符串或其他任何内容之前使用此代码:
boolean r = false;
boolean g = false;
for(int y = 0; y < height; y++) {
r = !r;
g = r;
for(int x = 0; x < width; x++) {
g = !g;
if(g) {
g2d.setColor(Color.GRAY);
}else {
g2d.setColor(Color.WHITE);
}
g2d.drawLine(x, y, x, y);
}
}
编辑 2
我建议您使用不同的字体。然后你不必做任何拉伸。好的字体是例如吉吉。您也可以 select 随机使用 GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()
一种字体,其中 returns Java 拥有的所有字体。