在 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 拥有的所有字体。