将随机文本转换为java中

时间:2018-04-02 13:22:38

标签: java captcha tapestry noise distortion

我正在我们的项目中实现验证码功能。它基本上是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) {
            }
     }

`

我是新手所以请明确告诉你什么。

先谢谢:-)

1 个答案:

答案 0 :(得分:0)

尝试阻止正在显示的文本时,您可以使用:

  • 点/圆圈,随机散布在不同大小和颜色的图像上
  • 线条,从图像边缘的随机点到图像边缘的另一个点。它们的颜色和厚度也各不相同。

据我所知,您可以使用g2d.drawLine(x1, y1, x2, y2)画一条线。由于您希望它从边缘移动到边缘上的另一个点,因此您必须限制随机点生成。您可以使用此方法:

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

如果你想为你的Captcha加一个虚线背景,你可以在渲染String或其他任何东西之前使用这段代码:

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

我建议你使用不同的字体。然后你不必做任何拉伸。好的字体就是例如吉吉。您还可以使用GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()随机选择一种字体,它返回Java所有的字体。