增加文字颜色与背景颜色色差设置

This commit is contained in:
Looly 2024-08-08 16:32:44 +08:00
parent 31495c7157
commit b5cba1db65
3 changed files with 188 additions and 50 deletions

View File

@ -83,7 +83,40 @@ public class GraphicsUtil {
* @since 4.5.10
*/
public static Graphics drawStringColourful(final Graphics g, final String str, final Font font, final int width, final int height) {
return drawString(g, str, font, null, width, height);
return drawStringColourful(g, str, font, width, height, null, 0);
}
/**
* 绘制字符串使用随机颜色默认抗锯齿
*
* @param g {@link Graphics}画笔
* @param str 字符串
* @param font 字体
* @param width 字符串总宽度
* @param height 字符串背景高度
* @param compareColor 对比颜色用于计算颜色与对比颜色的色差色差小于minColorDistance则重新生成颜色
* @param minColorDistance 随机生成的颜色与对比颜色的最小色差小于此值则重新生成颜色
* @return 画笔对象
* @since 6.0.0
*/
public static Graphics drawStringColourful(final Graphics g, final String str, final Font font,
final int width, final int height, final Color compareColor, final int minColorDistance) {
// 抗锯齿
enableAntialias(g);
// 创建字体
g.setFont(font);
// 文字高度必须在设置字体后调用
final int midY = getCenterY(g, height);
final int len = str.length();
final int charWidth = width / len;
for (int i = 0; i < len; i++) {
// 产生随机的颜色值让输出的每个字符的颜色值都将不同
g.setColor(ColorUtil.randomColor(compareColor, minColorDistance));
g.drawString(String.valueOf(str.charAt(i)), i * charWidth, midY);
}
return g;
}
/**
@ -93,12 +126,11 @@ public class GraphicsUtil {
* @param str 字符串
* @param font 字体
* @param color 字体颜色{@code null} 表示使用随机颜色每个字符单独随机
* @param width 字符串背景的宽度
* @param height 字符串背景的高度
* @return 画笔对象
* @since 4.5.10
* @since 6.0.0
*/
public static Graphics drawString(final Graphics g, final String str, final Font font, final Color color, final int width, final int height) {
public static Graphics drawString(final Graphics g, final String str, final Font font, final Color color, final int height) {
// 抗锯齿
enableAntialias(g);
// 创建字体
@ -109,16 +141,7 @@ public class GraphicsUtil {
if (null != color) {
g.setColor(color);
}
final int len = str.length();
final int charWidth = width / len;
for (int i = 0; i < len; i++) {
if (null == color) {
// 产生随机的颜色值让输出的每个字符的颜色值都将不同
g.setColor(ColorUtil.randomColor());
}
g.drawString(String.valueOf(str.charAt(i)), i * charWidth, midY);
}
g.drawString(str, 0, midY);
return g;
}
@ -222,9 +245,9 @@ public class GraphicsUtil {
private static void enableAntialias(final Graphics g) {
if (g instanceof Graphics2D) {
((Graphics2D) g).setRenderingHints(
RenderingHintsBuilder.of()
.setAntialiasing(RenderingHintsBuilder.Antialias.ON)
.setTextAntialias(RenderingHintsBuilder.TextAntialias.ON).build()
RenderingHintsBuilder.of()
.setAntialiasing(RenderingHintsBuilder.Antialias.ON)
.setTextAntialias(RenderingHintsBuilder.TextAntialias.ON).build()
);
}
}

View File

@ -40,28 +40,28 @@ public class ColorUtil {
static {
final Map<String, Color> colorMap = MapUtil
.builder("BLACK", Color.BLACK)
.put("WHITE", Color.WHITE)
.put("LIGHTGRAY", Color.LIGHT_GRAY)
.put("LIGHT_GRAY", Color.LIGHT_GRAY)
.put("GRAY", Color.GRAY)
.put("DARKGRAY", Color.DARK_GRAY)
.put("DARK_GRAY", Color.DARK_GRAY)
.put("RED", Color.RED)
.put("PINK", Color.PINK)
.put("ORANGE", Color.ORANGE)
.put("YELLOW", Color.YELLOW)
.put("GREEN", Color.GREEN)
.put("MAGENTA", Color.MAGENTA)
.put("CYAN", Color.CYAN)
.put("BLUE", Color.BLUE)
// 暗金色
.put("DARKGOLD", hexToColor("#9e7e67"))
.put("DARK_GOLD", hexToColor("#9e7e67"))
// 亮金色
.put("LIGHTGOLD", hexToColor("#ac9c85"))
.put("LIGHT_GOLD", hexToColor("#ac9c85"))
.build();
.builder("BLACK", Color.BLACK)
.put("WHITE", Color.WHITE)
.put("LIGHTGRAY", Color.LIGHT_GRAY)
.put("LIGHT_GRAY", Color.LIGHT_GRAY)
.put("GRAY", Color.GRAY)
.put("DARKGRAY", Color.DARK_GRAY)
.put("DARK_GRAY", Color.DARK_GRAY)
.put("RED", Color.RED)
.put("PINK", Color.PINK)
.put("ORANGE", Color.ORANGE)
.put("YELLOW", Color.YELLOW)
.put("GREEN", Color.GREEN)
.put("MAGENTA", Color.MAGENTA)
.put("CYAN", Color.CYAN)
.put("BLUE", Color.BLUE)
// 暗金色
.put("DARKGOLD", hexToColor("#9e7e67"))
.put("DARK_GOLD", hexToColor("#9e7e67"))
// 亮金色
.put("LIGHTGOLD", hexToColor("#ac9c85"))
.put("LIGHT_GOLD", hexToColor("#ac9c85"))
.build();
COLOR_MAPPING = MapUtil.view(colorMap);
}
@ -78,11 +78,11 @@ public class ColorUtil {
*/
public static String toCssRgb(final Color color) {
return StrUtil.builder()
.append("rgb(")
.append(color.getRed()).append(",")
.append(color.getGreen()).append(",")
.append(color.getBlue()).append(")")
.toString();
.append("rgb(")
.append(color.getRed()).append(",")
.append(color.getGreen()).append(",")
.append(color.getBlue()).append(")")
.toString();
}
/**
@ -93,12 +93,12 @@ public class ColorUtil {
*/
public static String toCssRgba(final Color color) {
return StrUtil.builder()
.append("rgba(")
.append(color.getRed()).append(",")
.append(color.getGreen()).append(",")
.append(color.getBlue()).append(",")
.append(color.getAlpha() / 255D).append(")")
.toString();
.append("rgba(")
.append(color.getRed()).append(",")
.append(color.getGreen()).append(",")
.append(color.getBlue()).append(",")
.append(color.getAlpha() / 255D).append(")")
.toString();
}
/**
@ -233,6 +233,8 @@ public class ColorUtil {
return new Color(r, g, b);
}
// region randomColor
/**
* 生成随机颜色
*
@ -257,6 +259,42 @@ public class ColorUtil {
return new Color(random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND), random.nextInt(RGB_COLOR_BOUND));
}
/**
* 生成随机颜色与指定颜色有一定的区分度
*
* @param compareColor 比较颜色{@code null}表示无区分要求
* @param minDistance 最小色差按三维坐标计算的距离值小于等于0表示无区分要求
* @return 随机颜色
* @since 5.8.30
*/
public static Color randomColor(final Color compareColor, final int minDistance) {
Color color = randomColor();
if(null == compareColor || minDistance <= 0){
while (computeColorDistance(compareColor, color) < minDistance) {
color = randomColor();
}
}
return color;
}
// endregion
/**
* 计算两个颜色之间的色差按三维坐标距离计算
*
* @param color1 颜色1
* @param color2 颜色2
* @return 色差按三维坐标距离值
* @since 5.8.30
*/
public static int computeColorDistance(final Color color1, final Color color2) {
if (null == color1 || null == color2) {
return 0;
}
return (int) Math.sqrt(Math.pow(color1.getRed() - color2.getRed(), 2)
+ Math.pow(color1.getGreen() - color2.getGreen(), 2)
+ Math.pow(color1.getBlue() - color2.getBlue(), 2));
}
/**
* AWT的{@link Color}颜色转换为ANSI颜色由于取最接近颜色故可能有色差
*

View File

@ -12,9 +12,20 @@
package org.dromara.hutool.swing.captcha;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.core.util.RandomUtil;
import org.dromara.hutool.swing.img.GraphicsUtil;
import org.dromara.hutool.swing.img.color.ColorUtil;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.concurrent.ThreadLocalRandom;
public class CaptchaUtilTest {
@Test
@ -24,4 +35,70 @@ public class CaptchaUtilTest {
CaptchaUtil.ofShearCaptcha(320, 240);
}
}
@Test
@Disabled
public void drawStringColourfulTest() {
for(int i = 0; i < 10; i++) {
final AbstractCaptcha lineCaptcha = new TestLineCaptcha(200, 100, 5, 10);
lineCaptcha.write("d:/captcha/line"+i+".png");
}
}
static class TestLineCaptcha extends AbstractCaptcha{
private static final long serialVersionUID = -558846929114465692L;
public TestLineCaptcha(final int width, final int height, final int codeCount, final int interfereCount) {
super(width, height, codeCount, interfereCount);
}
@Override
protected Image createImage(final String code) {
// 图像buffer
final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
final Graphics2D g = GraphicsUtil.createGraphics(image, ObjUtil.defaultIfNull(this.background, Color.WHITE));
// 干扰线
drawInterfere(g);
// 字符串
drawString(g, code);
return image;
}
// ----------------------------------------------------------------------------------------------------- Private method start
/**
* 绘制字符串
*
* @param g {@link Graphics}画笔
* @param code 验证码
*/
private void drawString(final Graphics2D g, final String code) {
// 指定透明度
if (null != this.textAlpha) {
g.setComposite(this.textAlpha);
}
GraphicsUtil.drawStringColourful(g, code, this.font, this.width, this.height,Color.WHITE,200);
}
/**
* 绘制干扰线
*
* @param g {@link Graphics2D}画笔
*/
private void drawInterfere(final Graphics2D g) {
final ThreadLocalRandom random = RandomUtil.getRandom();
// 干扰线
for (int i = 0; i < this.interfereCount; i++) {
final int xs = random.nextInt(width);
final int ys = random.nextInt(height);
final int xe = xs + random.nextInt(width / 3);
final int ye = ys + random.nextInt(height / 3);
g.setColor(ColorUtil.randomColor(random));
g.drawLine(xs, ys, xe, ye);
}
}
// ----------------------------------------------------------------------------------------------------- Private method start
}
}