欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實(shí)現(xiàn)簡(jiǎn)單文字驗(yàn)證碼以及人機(jī)驗(yàn)證

 更新時(shí)間:2025年04月08日 10:25:05   作者:The_cute_cat  
人機(jī)驗(yàn)證技術(shù)的發(fā)展也在不斷進(jìn)化,從最初的簡(jiǎn)單驗(yàn)證碼到現(xiàn)在的人工智能驅(qū)動(dòng)的高級(jí)驗(yàn)證系統(tǒng),下面這篇文章主要介紹了Java實(shí)現(xiàn)簡(jiǎn)單文字驗(yàn)證碼以及人機(jī)驗(yàn)證的相關(guān)資料,需要的朋友可以參考下

一、代碼引用

首先,如果你想直接用,可以直接用下面這個(gè)類。

可以調(diào)用CaptchaGenerator類中的captchaCreateImage方法,其方法參數(shù)列表為(int width, int height, int captchaLength, String[] returnCaptcha, int degree),方法返回驗(yàn)證碼圖像

width -----------------------文字驗(yàn)證碼圖片的寬度

height-----------------------文字驗(yàn)證碼圖片的高度

captchaLength-----------文字驗(yàn)證碼的長(zhǎng)度

returnCaptcha-----------返回的文字驗(yàn)證碼

degree---------------------干擾的程度(1-5,不在范圍默認(rèn)為5)

程度展示

 代碼引用處

import java.awt.*; // 導(dǎo)入 AWT 圖形庫(kù)
import java.awt.geom.AffineTransform; // 導(dǎo)入用于執(zhí)行幾何變換的類
import java.awt.image.BufferedImage; // 導(dǎo)入用于處理圖像的類
import java.util.Random; // 導(dǎo)入隨機(jī)數(shù)生成器類
import java.util.concurrent.ThreadLocalRandom;

public class CaptchaGenerator {
    // 創(chuàng)建隨機(jī)數(shù)生成器
    private final Random random = ThreadLocalRandom.current();

    // 創(chuàng)建驗(yàn)證碼的方法
    private String createCaptcha(int length) {
        // 定義可選字符池(不包含容易混淆的字符0和O等)
        String charPool = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789";
        StringBuilder result = new StringBuilder(); // 用于構(gòu)建驗(yàn)證碼字符串

        // 隨機(jī)選擇字符生成驗(yàn)證碼
        for (int i = 0; i < length; i++) {
            result.append(charPool.charAt(random.nextInt(charPool.length()))); // 從字符池中隨機(jī)選擇字符
        }
        return result.toString(); // 返回生成的驗(yàn)證碼字符串
    }

    // 創(chuàng)建顏色的方法,生成指定范圍內(nèi)隨機(jī)顏色
    private Color createColor(int min, int max) {
        int r = min + random.nextInt(max - min+1); // 隨機(jī)生成紅色分量
        int g = min + random.nextInt(max - min+1); // 隨機(jī)生成綠色分量
        int b = min + random.nextInt(max - min+1); // 隨機(jī)生成藍(lán)色分量
        return new Color(r, g, b); // 創(chuàng)建并返回顏色對(duì)象
    }

    // 添加干擾元素的方法
    private void addInterference(Graphics2D g, int degree, int width, int height) {
        // 確保干擾元素的數(shù)量在0到5之間
        degree = (degree <= 0 || degree > 5) ? 5 : degree;

        // 根據(jù)度數(shù)生成干擾元素
        for (int i = 0; i < degree * 20; i++) {
            int x = random.nextInt(width); // 隨機(jī)生成x坐標(biāo)
            int y = random.nextInt(height); // 隨機(jī)生成y坐標(biāo)

            // 隨機(jī)選擇干擾元素的顏色
            Color color = (random.nextBoolean()) ? createColor(0, 255) : ((random.nextBoolean()) ? Color.WHITE : Color.BLACK);
            g.setColor(color); // 設(shè)置畫(huà)筆顏色

            // 隨機(jī)選擇干擾元素的類型并畫(huà)出
            switch (random.nextInt(3)) {
                case 0 -> g.fillOval(x, y, random.nextInt(3) + 1, random.nextInt(3) + 1); // 畫(huà)圓點(diǎn)
                case 1 -> {
                    int change = random.nextInt(3); // 隨機(jī)變化值
                    // 畫(huà)出線條構(gòu)成的隨機(jī)圖形
                    g.drawLine(x, y, x + change, y + change);
                    g.drawLine(x + change, y + change, x + 2 * change, y);
                    g.drawLine(x, y, x + change, y - change);
                    g.drawLine(x + change, y - change, x + 2 * change, y);
                }
                case 2 -> g.drawLine(x, y, x + random.nextInt(5) + 1, y + random.nextInt(5) + 1); // 畫(huà)線
            }
        }

        // 生成更多隨機(jī)干擾線
        for (int i = 0; i < 5 * degree; i++) {
            Color color = (random.nextBoolean()) ? createColor(0, 255) : ((random.nextBoolean()) ? Color.WHITE : Color.BLACK);
            g.setColor(color);
            // 隨機(jī)生成干擾線的起止點(diǎn)
            g.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width), random.nextInt(height));
        }
    }

    // 創(chuàng)建驗(yàn)證碼圖像的方法
    private BufferedImage createImage(int width, int height, int captchaLength, String[] returnCaptcha, int degree) {

        // 創(chuàng)建新圖像
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics(); // 獲取圖形上下文
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 啟用抗鋸齒

        // 創(chuàng)建背景色
        Color backgroundColor = createColor(0, 255);
        g.setColor(backgroundColor);
        g.fillRect(0, 0, width, height); // 填充背景

        // 生成驗(yàn)證碼
        String captcha = createCaptcha(captchaLength);
        returnCaptcha[0] = captcha; // 將生成的驗(yàn)證碼存入數(shù)組

        // 設(shè)置字體大小和干擾詳細(xì)參數(shù)
        int fontSize = (int) (height * 0.5);
        AffineTransform at = new AffineTransform(); // 創(chuàng)建變換對(duì)象
        at.shear(random.nextDouble() * 0.4 - 0.2, random.nextDouble() * 0.4 - 0.2); // 隨機(jī)傾斜變換

        Font font = new Font(Font.SANS_SERIF, Font.BOLD, fontSize); // 創(chuàng)建字體對(duì)象
        font = font.deriveFont(at); // 生成傾斜字體

        addInterference(g, degree, width, height); // 添加干擾元素

        Color fontColor, prevFontColor = null; // 字體顏色和前一個(gè)字體顏色
        int fontX, fontY, fontWidth, changeX; // 不同的坐標(biāo)和寬度
        FontMetrics fontMetrics = g.getFontMetrics(); // 字體度量
        fontWidth = fontMetrics.stringWidth(captcha) + (captchaLength - 1) * (int) (width * 0.05); // 計(jì)算驗(yàn)證碼的寬度
        fontX = (width - fontWidth) / 2; // 計(jì)算x坐標(biāo)以居中對(duì)齊
        fontY = (height - (fontMetrics.getAscent() + fontMetrics.getDescent())) / 2 + fontMetrics.getAscent(); // 計(jì)算y坐標(biāo)

        double tempX = fontX; // 保存當(dāng)前x坐標(biāo)

        // 逐個(gè)繪制驗(yàn)證碼字符
        for (int i = 0; i < captchaLength; i++) {
            // 根據(jù)背景色的亮度生成對(duì)比度較強(qiáng)的字體顏色
            fontColor = (backgroundColor.getRed() > 180) ? createColor(0, 160) : createColor(200, 255);
            int maxAttempts = 10,count=0;//設(shè)置最大循環(huán)數(shù),避免死循環(huán)
            // 確保字體顏色與前一個(gè)字體顏色不相近
            while (prevFontColor != null&&count++<maxAttempts) {
                double brightness = (backgroundColor.getRed() * 299 + backgroundColor.getBlue() * 114 + backgroundColor.getGreen() * 587) / 1000.0;
                fontColor = (brightness > 128) ? createColor(0, 128) : createColor(128, 255); // 確定字體顏色
                int dr = fontColor.getBlue() - prevFontColor.getBlue();
                int dg = fontColor.getGreen() - prevFontColor.getGreen();
                int db = fontColor.getRed() - prevFontColor.getRed();
                prevFontColor = fontColor; // 更新前一個(gè)顏色
                // 如果顏色差異大于亮度則退出循環(huán)
                if (Math.sqrt(dr * dr + dg * dg + db * db) > brightness) break;
            }

            prevFontColor = fontColor; // 更新前一個(gè)顏色
            g.setFont(font); // 設(shè)置當(dāng)前字體
            g.setColor(fontColor); // 設(shè)置當(dāng)前字體顏色

            // 隨機(jī)旋轉(zhuǎn)角度
            int RotationAngle = random.nextInt(60) - 30;
            g.rotate(Math.toRadians(RotationAngle), tempX, fontY); // 繞中心點(diǎn)旋轉(zhuǎn)
            // 繪制字符
            g.drawString(String.valueOf(captcha.charAt(i)), (int) tempX, fontY);
            g.rotate(-Math.toRadians(RotationAngle), tempX, fontY); // 逆旋轉(zhuǎn)恢復(fù)狀態(tài)

            changeX = fontMetrics.stringWidth(String.valueOf(captcha.charAt(i))); // 獲取當(dāng)前字符寬度
            tempX += (changeX + (int) (width * 0.05)); // 更新臨時(shí)x坐標(biāo),為下一個(gè)字符準(zhǔn)備空間
        }
        g.dispose(); // 釋放圖形上下文資源
        if(captchaLength <= 0|| returnCaptcha[0].isEmpty()) {
            throw new IllegalArgumentException("returnCaptcha array must be non-null and have at least one element");
        }
        return image; // 返回生成的圖像
    }
    public BufferedImage captchaCreateImage(int width, int height, int captchaLength, String[] returnCaptcha, int degree){
        return createImage(width, height, captchaLength, returnCaptcha, degree);
    }
}

二、代碼實(shí)現(xiàn)

1.生成驗(yàn)證碼

由于0和O等字符容易混淆,因此需要去除這些字符。

private String createCaptcha(int length){
        String charPool = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789";
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < length; i++) {
            result.append(charPool.charAt(random.nextInt(charPool.length())));
        }
        return result.toString();
    }

2.生成圖片前的準(zhǔn)備

(1)創(chuàng)建一個(gè)指定寬度、高度和類型的BufferedImage對(duì)象

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

(2)獲取Graphics2D對(duì)象,用于繪制圖像,并啟用抗鋸齒

Graphics2D g = image.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

(3)填充背景顏色

Color backgroundColor = createColor(0, 255); // 隨機(jī)生成背景顏色
g.setColor(backgroundColor); // 設(shè)置背景顏色
g.fillRect(0, 0, width, height); // 填充背景色

(4)獲取驗(yàn)證碼

String captcha = createCaptcha(captchaLength);
returnCaptcha[0]=captcha;

3.圖片添加干擾

總體預(yù)覽

private void addInterference(Graphics2D g,int degree,int width,int height){
        degree=(degree <= 0||degree > 5)?5:degree;
        for (int i = 0; i < degree*20; i++) {
            int x=random.nextInt(width);
            int y=random.nextInt(height);
            Color color=(random.nextBoolean())?createColor(0,255):((random.nextBoolean())?Color.WHITE:Color.BLACK);
            g.setColor(color);
            switch (random.nextInt(3)){
                case 0-> g.fillOval(x,y, random.nextInt(3)+1,random.nextInt(3)+1);
                case 1-> {
                    int change=random.nextInt(3);
                    g.drawLine(x,y,x+change,y+change);
                    g.drawLine(x+change,y+change,x+2*change,y);
                    g.drawLine(x,y,x+change,y-change);
                    g.drawLine(x+change,y-change,x+2*change,y);
                }
                case 2->g.drawLine(x,y,x+random.nextInt(5)+1,y+random.nextInt(5)+1);
            }
        }
        for(int i=0;i<5*degree;i++){
            Color color=(random.nextBoolean())?createColor(0,255):((random.nextBoolean())?Color.WHITE:Color.BLACK);
            g.setColor(color);
            g.drawLine(random.nextInt(width),random.nextInt(height),random.nextInt(width),random.nextInt(height));
        }
    }

(1)確保程度合法

degree=(degree <= 0||degree > 5)?5:degree;

(2)生成噪點(diǎn)

a.隨機(jī)坐標(biāo)

int x=random.nextInt(width);
int y=random.nextInt(height);

b.顏色設(shè)置

要么彩色,要么黑白。

Color color=(random.nextBoolean())?createColor(0,255):((random.nextBoolean())?Color.WHITE:Color.BLACK);
g.setColor(color);

 c.噪點(diǎn)樣式選擇

總體預(yù)覽

switch (random.nextInt(3)){
                case 0-> g.fillOval(x,y, random.nextInt(3)+1,random.nextInt(3)+1);
                case 1-> {
                    int change=random.nextInt(3);
                    g.drawLine(x,y,x+change,y+change);
                    g.drawLine(x+change,y+change,x+2*change,y);
                    g.drawLine(x,y,x+change,y-change);
                    g.drawLine(x+change,y-change,x+2*change,y);
                }
                case 2->g.drawLine(x,y,x+random.nextInt(5)+1,y+random.nextInt(5)+1);
            }

1.橢圓形

case 0-> g.fillOval(x,y, random.nextInt(3)+1,random.nextInt(3)+1);

 2.菱形

case 1-> {
                    int change=random.nextInt(3);
                    g.drawLine(x,y,x+change,y+change);
                    g.drawLine(x+change,y+change,x+2*change,y);
                    g.drawLine(x,y,x+change,y-change);
                    g.drawLine(x+change,y-change,x+2*change,y);
                }

3.隨機(jī)短線段

case 2->g.drawLine(x,y,x+random.nextInt(5)+1,y+random.nextInt(5)+1);

4.驗(yàn)證碼內(nèi)容處理

(1)處理字體

總體預(yù)覽

int fontSize=(int)(height*0.5);
AffineTransform at = new AffineTransform();
at.shear(random.nextDouble()*0.4-0.2,random.nextDouble()*0.4-0.2);
Font font=new Font("微軟雅黑", Font.BOLD,fontSize);
font=font.deriveFont(at);
g.setFont(font);

a.設(shè)置字體大小

int fontSize=(int)(height*0.5);

b.創(chuàng)建AffineTransform對(duì)象,用于幾何變換,將字體扭曲,程度為[-0.2,0.2]。

AffineTransform at = new AffineTransform();
at.shear(random.nextDouble()*0.4-0.2,random.nextDouble()*0.4-0.2);

c.設(shè)置字體樣式,并應(yīng)用扭曲

Font font=new Font("微軟雅黑", Font.BOLD,fontSize);
font=font.deriveFont(at);

(2)字符居中處理

總體預(yù)覽

int fontX,fontY,fontWidth,changeX;
FontMetrics fontMetrics = g.getFontMetrics();
fontWidth=fontMetrics.stringWidth(captcha)+(captchaLength-1)*(int)(width*0.05);
fontX=(width-fontWidth)/2;
fontY=(height - (fontMetrics.getAscent() + fontMetrics.getDescent())) / 2 + fontMetrics.getAscent();

a.獲取橫坐標(biāo)

fontMetrics.stringWidth(captcha)是所有的字符的總寬度。

(captchaLength-1)*(int)(width*0.05)是字符之間的總間隔大小,其中(captchaLength-1)為間隔數(shù),(width*0.05)為間隔大小。

fontWidth=fontMetrics.stringWidth(captcha)+(captchaLength-1)*(int)(width*0.05);
fontX=(width-fontWidth)/2;

b.獲取縱坐標(biāo)

FontMetrics fontMetrics = g.getFontMetrics();
fontY=(height - (fontMetrics.getAscent() + fontMetrics.getDescent())) / 2 + fontMetrics.getAscent();

fontMetrics.getAscent():基線到字體最高點(diǎn)的距離

fontMetrics.getDescent():基線到字體最低點(diǎn)的距離

怎么理解?

FontMetrics類提供了關(guān)鍵參數(shù):

  • Ascent:基線到字體最高點(diǎn)的距離(如字母"h"的頂部)。

  • Descent:基線到字體最低點(diǎn)的距離(如字母"g"的尾部)。

  • Leading:行間距(通常較?。?。

  • Height:總高度(Ascent + Descent + Leading)。

一、將文字想象成一個(gè)“盒子”

假設(shè)每個(gè)字符是一個(gè)矩形盒子,其高度由三部分組成:

  • Ascent(上升) :基線(baseline)到盒子頂部的距離(如字母"h"的頂部)。

  • Descent(下降) :基線到盒子底部的距離(如字母"g"的尾部)。

  • Leading(行間距) :盒子下方預(yù)留的空白(通常很小,可暫時(shí)忽略)。 

二、Java繪圖的“基線對(duì)齊”

當(dāng)調(diào)用 g.drawString(text, x, y) 時(shí):

  • 參數(shù)y是基線的位置,而非文字區(qū)域的頂部或中心。

  • 如果直接將畫(huà)布中點(diǎn)(height/2)作為基線位置,文字會(huì)整體偏下,因?yàn)锳scent部分會(huì)向上延伸,而Descent部分會(huì)向下延伸。

畫(huà)布頂部(y=50)
|        |
|        |
|      —————————— ← Ascent(y=35)
|        
|      —————————— ← 基線(y=30)
|        
|      —————————— ← 畫(huà)布中心(y=25)
|        ▲
|        | 
|        ▼
|      —————————— ← Descent(y=15)
|        |
|        |
畫(huà)布底部(y=0)

(3)字符顏色處理

總體預(yù)覽

fontColor=(backgroundColor.getRed()>180)?createColor(0,160):createColor(200,255);
            int maxAttempts = 10,count=0;
            while (prevFontColor!=null&&count++<maxAttempts) {
                double brightness=(backgroundColor.getRed()*299+backgroundColor.getBlue()*114+backgroundColor.getGreen()*587)/1000.0;
                fontColor=(brightness>128)?createColor(0,128):createColor(128,255);
                int dr=fontColor.getBlue()-prevFontColor.getBlue();
                int dg=fontColor.getGreen()-prevFontColor.getGreen();
                int db=fontColor.getRed()-prevFontColor.getRed();
                prevFontColor=fontColor;
                if(Math.sqrt(dr*dr+dg*dg+db*db)>brightness)break;
            }
            prevFontColor=fontColor;
            g.setColor(fontColor);

a.隨機(jī)顏色

避免與背景顏色相近。

fontColor=(backgroundColor.getRed()>180)?createColor(0,160):createColor(200,255);

b.處理相鄰顏色相近與對(duì)比度不明顯問(wèn)題

總體預(yù)覽

while (prevFontColor!=null&&count++<maxAttempts) {
                double brightness=(backgroundColor.getRed()*299+backgroundColor.getBlue()*114+backgroundColor.getGreen()*587)/1000.0;
                fontColor=(brightness>128)?createColor(0,128):createColor(128,255);
                int dr=fontColor.getBlue()-prevFontColor.getBlue();
                int dg=fontColor.getGreen()-prevFontColor.getGreen();
                int db=fontColor.getRed()-prevFontColor.getRed();
                prevFontColor=fontColor;
                if(Math.sqrt(dr*dr+dg*dg+db*db)>brightness)break;
            }
            prevFontColor=fontColor;

1.顏色差異檢測(cè)機(jī)制(歐氏距離)

顏色距離公式

使用歐氏距離公式計(jì)算顏色差異:

\Delta = \sqrt{(R_1-R_2)^2 + (G_1-G_2)^2 + (B_1-B_2)^2}

該公式能綜合衡量RGB三個(gè)通道的差異,更符合人眼對(duì)顏色差異的感知

2.背景對(duì)比度優(yōu)化(YIQ模型)

  • YIQ亮度模型
    使用公式:

    Y = 0.299R + 0.587G + 0.114B
    

    該模型更貼近人眼對(duì)亮度的敏感度(綠色權(quán)重最高,藍(lán)色最低)。

  • 對(duì)比度標(biāo)準(zhǔn)

    • 若背景亮度Y > 128(亮色背景),選擇深色字體(如黑色、深藍(lán))

    • Y ≤ 128(暗色背景),選擇淺色字體(如白色、亮黃)

      綜合效果

    • 抗機(jī)器識(shí)別

      • 顏色差異和色相跳躍破壞OCR工具的顏色聚類算法,使其難以分割相鄰字符。

      • 邊緣描邊干擾輪廓識(shí)別算法。

    • 人類可讀性

      • 高對(duì)比度確保文字清晰,符合人眼對(duì)亮度、色相的敏感特性。

      • 隨機(jī)旋轉(zhuǎn)和扭曲保留驗(yàn)證碼的防機(jī)器特性,但不會(huì)影響人類閱讀。

(4)字符旋轉(zhuǎn)處理

總體預(yù)覽

int RotationAngle=random.nextInt(60)-30;
g.rotate(Math.toRadians(RotationAngle),tempX,fontY);
g.drawString(String.valueOf(captcha.charAt(i)),(int)tempX,fontY);
g.rotate(-Math.toRadians(RotationAngle),tempX,fontY);
changeX=fontMetrics.stringWidth(String.valueOf(captcha.charAt(i)));
tempX+=(changeX+(int)(width*0.05));

a.隨機(jī)角度[-30°,30°]

int RotationAngle=random.nextInt(60)-30;

b.旋轉(zhuǎn)字符

1.旋轉(zhuǎn)畫(huà)布

g.rotate(Math.toRadians(RotationAngle),tempX,fontY);
  • g.rotate(double theta, double x, double y) 方法用于旋轉(zhuǎn)當(dāng)前的 Graphics 上下文,影響之后的繪圖操作。

    • Math.toRadians(RotationAngle):將角度從度轉(zhuǎn)換為弧度,因?yàn)?Java 的 rotate 方法需要以弧度為單位的旋轉(zhuǎn)角度。

    • tempX 和 fontY:這里指定了旋轉(zhuǎn)中心的坐標(biāo)。

      • tempX:是文本的當(dāng)前 x 坐標(biāo),通常根據(jù)文本的長(zhǎng)度動(dòng)態(tài)計(jì)算,使得字符繪制在適當(dāng)?shù)奈恢谩?/p>

      • fontY:是文本的 y 坐標(biāo),通常是一個(gè)固定值,確保文本在畫(huà)布的某一高度。

通過(guò)這行代碼,當(dāng)前畫(huà)布將圍繞指定的 (tempX, fontY) 點(diǎn)旋轉(zhuǎn),旋轉(zhuǎn)角度為 RotationAngle。

2.繪制字符 

g.drawString(String.valueOf(captcha.charAt(i)),(int)tempX,fontY);
  • g.drawString(String str, int x, int y) 方法用于在畫(huà)布上繪制字符串。

  • String.valueOf(captcha.charAt(i)):從名為 captcha 的字符串中獲取索引為 i 的字符,并將其轉(zhuǎn)換為字符串(通常可以直接使用 captcha.charAt(i))。

  • (int)tempX 和 fontY:這是繪制文本的坐標(biāo)。

    • tempX:是在之前計(jì)算的 x 坐標(biāo),代表文本在水平方向上的位置。

    • fontY:是文本在垂直方向上的固定高度。

這行代碼則在旋轉(zhuǎn)后的畫(huà)布上繪制當(dāng)前字符。

3.恢復(fù)畫(huà)布的旋轉(zhuǎn)狀態(tài)

g.rotate(-Math.toRadians(RotationAngle),tempX,fontY);
  • 這行代碼用于撤銷之前的旋轉(zhuǎn)操作。

    • -Math.toRadians(RotationAngle):使用負(fù)的角度進(jìn)行旋轉(zhuǎn),與之前的旋轉(zhuǎn)相反。

    • tempX 和 fontY:依然是旋轉(zhuǎn)中心的坐標(biāo)。

這個(gè)步驟確保在繪制完當(dāng)前字符后,畫(huà)布的狀態(tài)返回到原始位置,方便后續(xù)繪制其他字符時(shí)不會(huì)受到影響。

c.繪制字符位置處理

changeX=fontMetrics.stringWidth(String.valueOf(captcha.charAt(i)));
tempX+=(changeX+(int)(width*0.05));

1. 計(jì)算字符寬度

  • captcha.charAt(i):從 captcha 字符串中獲取索引 i 處的字符。這是當(dāng)前需要繪制的字符。

  • String.valueOf(...):將獲取的字符轉(zhuǎn)換為字符串。雖然在 Java 中,char 類型可以直接用于字符串操作,但使用 String.valueOf 方法能確保我們?cè)谛枰獣r(shí)轉(zhuǎn)換為字符串類型。

  • fontMetrics.stringWidth(...):這個(gè)方法是 FontMetrics 類中的一個(gè)方法,它可以返回指定字符串在當(dāng)前字體下的寬度(以像素為單位)。也就是說(shuō),它計(jì)算出當(dāng)前正在使用的字體繪制 String.valueOf(captcha.charAt(i)) 這一個(gè)字符所需要的寬度。

  • changeX:這是一個(gè)變量,用于存儲(chǔ)當(dāng)前字符的寬度。這將被用來(lái)調(diào)整下一個(gè)字符的繪制位置。

2.更新繪制位置

  • tempX:這是一個(gè)變量,表示當(dāng)前字符在繪圖上下文中的 x 坐標(biāo)。它記錄了下一個(gè)字符應(yīng)該繪制的 horizontal (水平方向) 位置。

  • changeX:上面計(jì)算獲得的當(dāng)前字符寬度。

  • (int)(width * 0.05):這部分代碼用于在字符之間添加一定的間距。在這里,width 是整張圖片的寬度,而 width * 0.05 表示取寬度的 5%。通過(guò)將結(jié)果轉(zhuǎn)換為 int,確保我們將這個(gè)浮點(diǎn)值作為整數(shù)處理,適配繪圖 API 對(duì)坐標(biāo)的要求。

  • +=:這個(gè)操作符用于將當(dāng)前的 tempX 值加上當(dāng)前字符的寬度和額外的間距,然后更新 tempX 的值。這一步確保下一個(gè)字符繪制時(shí)不會(huì)重疊,而是位于上一個(gè)字符的右側(cè),并且留有一定的間隙。

總結(jié) 

到此這篇關(guān)于Java實(shí)現(xiàn)簡(jiǎn)單文字驗(yàn)證碼以及人機(jī)驗(yàn)證的文章就介紹到這了,更多相關(guān)Java文字驗(yàn)證碼及人機(jī)驗(yàn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring Boot高級(jí)教程之使用Redis實(shí)現(xiàn)session共享

    Spring Boot高級(jí)教程之使用Redis實(shí)現(xiàn)session共享

    這篇文章主要為大家詳細(xì)介紹了Spring Boot高級(jí)教程之使用Redis實(shí)現(xiàn)session共享,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • java中使用logger打印日志有哪些坑

    java中使用logger打印日志有哪些坑

    在Java中使用日志記錄器(Logger)打印日志時(shí),確實(shí)存在一些常見(jiàn)的坑需要注意,本文就來(lái)介紹一下幾種方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-05-05
  • 基于Process#waitFor()阻塞問(wèn)題的解決

    基于Process#waitFor()阻塞問(wèn)題的解決

    這篇文章主要介紹了Process#waitFor()阻塞問(wèn)題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java toString方法重寫(xiě)工具之ToStringBuilder案例詳解

    Java toString方法重寫(xiě)工具之ToStringBuilder案例詳解

    這篇文章主要介紹了Java toString方法重寫(xiě)工具之ToStringBuilder案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • SpringCloud客戶端的負(fù)載均衡Ribbon的實(shí)現(xiàn)

    SpringCloud客戶端的負(fù)載均衡Ribbon的實(shí)現(xiàn)

    微服務(wù)架構(gòu),不可避免的存在單個(gè)微服務(wù)有多個(gè)實(shí)例,這篇文章主要介紹了SpringCloud客戶端的負(fù)載均衡Ribbon的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • 被kafka-client和springkafka版本坑到自閉及解決

    被kafka-client和springkafka版本坑到自閉及解決

    這篇文章主要介紹了被kafka-client和springkafka版本坑到自閉及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Spring cloud Gateway簡(jiǎn)介及相關(guān)配置方法

    Spring cloud Gateway簡(jiǎn)介及相關(guān)配置方法

    這篇文章主要介紹了Spring cloud Gateway簡(jiǎn)介及相關(guān)配置方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • Java里遍歷Map集合的多種方法總結(jié)

    Java里遍歷Map集合的多種方法總結(jié)

    Java中的Map是一種鍵值對(duì)映射的數(shù)據(jù)結(jié)構(gòu),它提供了一些常用的方法用于獲取、添加、刪除和修改元素,在Java中,有多種方式可以遍歷Map,本文將介紹其中的四種常用方式,并比較它們之間的優(yōu)缺點(diǎn),需要的朋友可以參考下
    2024-07-07
  • Spring Boot實(shí)戰(zhàn)之發(fā)送郵件示例代碼

    Spring Boot實(shí)戰(zhàn)之發(fā)送郵件示例代碼

    本篇文章主要介紹了Spring Boot實(shí)戰(zhàn)之發(fā)送郵件示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2017-03-03
  • Java實(shí)現(xiàn)List集合手動(dòng)分頁(yè)的方法

    Java實(shí)現(xiàn)List集合手動(dòng)分頁(yè)的方法

    在工作中難免會(huì)遇到,將組裝的集合數(shù)據(jù)進(jìn)行分頁(yè)處理,本文主要介紹了Java實(shí)現(xiàn)List集合手動(dòng)分頁(yè)的方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03

最新評(píng)論